1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-01 04:24:19 +00:00
arikawa/gateway/events.go

1061 lines
35 KiB
Go

package gateway
import (
"errors"
"strconv"
"strings"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/diamondburned/arikawa/v3/utils/json"
"github.com/diamondburned/arikawa/v3/utils/json/option"
"github.com/diamondburned/arikawa/v3/utils/ws"
)
//go:generate go run ../utils/cmd/genevent -o event_methods.go
// ReadyEventKeepRaw, if true, will make the gateway keep a copy of the raw JSON
// body that makes up the Ready event. This is useful for non-bots.
var ReadyEventKeepRaw = false
// Event is a type alias for ws.Event. It exists for convenience and describes
// the same event as any other ws.Event.
type Event ws.Event
// Rule: VOICE_STATE_UPDATE -> VoiceStateUpdateEvent.
// Ready is too big, so it's moved to ready.go.
const (
dispatchOp ws.OpCode = 0 // recv
heartbeatOp ws.OpCode = 1 // send/recv
identifyOp ws.OpCode = 2 // send...
statusUpdateOp ws.OpCode = 3 //
voiceStateUpdateOp ws.OpCode = 4 //
voiceServerPingOp ws.OpCode = 5 //
resumeOp ws.OpCode = 6 //
reconnectOp ws.OpCode = 7 // recv
requestGuildMembersOp ws.OpCode = 8 // send
invalidSessionOp ws.OpCode = 9 // recv...
helloOp ws.OpCode = 10
heartbeatAckOp ws.OpCode = 11
callConnectOp ws.OpCode = 13
guildSubscriptionsOp ws.OpCode = 14
)
// OpUnmarshalers contains the Op unmarshalers for this gateway.
var OpUnmarshalers = ws.NewOpUnmarshalers()
// HeartbeatCommand is a command for Op 1. It is the last sequence number to be
// sent.
type HeartbeatCommand int
// HeartbeatAckEvent is an event for Op 11.
type HeartbeatAckEvent struct{}
// ReconnectEvent is an event for Op 7.
type ReconnectEvent struct{}
// HelloEvent is an event for Op 10.
//
// https://discord.com/developers/docs/topics/gateway#connecting-and-resuming
type HelloEvent struct {
HeartbeatInterval discord.Milliseconds `json:"heartbeat_interval"`
}
// ResumeCommand is a command for Op 6. It describes the Resume send command.
// This is not to be confused with ResumedEvent, which is an event that Discord
// sends us.
type ResumeCommand struct {
Token string `json:"token"`
SessionID string `json:"session_id"`
Sequence int64 `json:"seq"`
}
// InvalidSessionEvent is an event for Op 9. It indicates if the event is
// resumable.
//
// https://discord.com/developers/docs/topics/gateway#connecting-and-resuming
type InvalidSessionEvent bool
// RequestGuildMembersCommand is a command for Op 8. Either UserIDs or (Query
// and Limit) must be filled.
type RequestGuildMembersCommand struct {
// GuildIDs contains the IDs of the guilds to request data from. Multiple
// guilds can only be requested when using user accounts.
//
// The guild_id JSON key is intentional, despite the type being an array.
GuildIDs []discord.GuildID `json:"guild_id"`
// UserIDs contains the IDs of the users to request data for. If this is
// filled, then the Query field must be empty.
UserIDs []discord.UserID `json:"user_ids,omitempty"`
// Query is a string to search for matching usernames. If this is filled,
// then the UserIDs field must be empty. If Query is empty, then all members
// are filled for bots.
Query option.String `json:"query,omitempty"`
// Limit is used to specify the maximum number of members to send back when
// Query is used.
Limit uint `json:"limit,omitempty"`
Presences bool `json:"presences"`
Nonce string `json:"nonce,omitempty"`
}
// MarshalJSON marshals a RequestGuildMembersCommand.
func (c *RequestGuildMembersCommand) MarshalJSON() ([]byte, error) {
type raw RequestGuildMembersCommand
if c.UserIDs != nil && c.Query != nil {
return nil, errors.New("neither UserIDs nor Query can be filled")
}
var marshaling interface{} = (*raw)(c)
if c.Query != nil {
// Force the Limit field to be present if Query is present.
marshaling = struct {
*raw
Limit uint `json:"limit"`
}{
raw: (*raw)(c),
Limit: c.Limit,
}
}
return json.Marshal(marshaling)
}
// UpdateVoiceStateCommand is a command for Op 4.
type UpdateVoiceStateCommand struct {
GuildID discord.GuildID `json:"guild_id"`
ChannelID discord.ChannelID `json:"channel_id"` // nullable
SelfMute bool `json:"self_mute"`
SelfDeaf bool `json:"self_deaf"`
}
// UpdatePresenceCommand is a command for Op 3. It is sent by this client to
// indicate a presence or status update.
type UpdatePresenceCommand struct {
Since discord.UnixMsTimestamp `json:"since"` // 0 if not idle
// Activities can be null or an empty slice.
Activities []discord.Activity `json:"activities"`
Status discord.Status `json:"status"`
AFK bool `json:"afk"`
}
// GuildSubscribeCommand is a command for Op 14. It is undocumented.
type GuildSubscribeCommand struct {
Typing bool `json:"typing"`
Threads bool `json:"threads"`
Activities bool `json:"activities"`
GuildID discord.GuildID `json:"guild_id"`
// Channels is not documented. It's used to fetch the right members sidebar.
Channels map[discord.ChannelID][][2]int `json:"channels,omitempty"`
}
// ResumedEvent is a dispatch event. It is sent by Discord whenever we've
// successfully caught up to all events after resuming.
type ResumedEvent struct{}
// ChannelCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#channels
type ChannelCreateEvent struct {
discord.Channel
}
// ChannelUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#channels
type ChannelUpdateEvent struct {
discord.Channel
}
// ChannelDeleteEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#channels
type ChannelDeleteEvent struct {
discord.Channel
}
// ChannelPinsUpdateEvent is a dispatch event.
type ChannelPinsUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id,omitempty"`
ChannelID discord.ChannelID `json:"channel_id,omitempty"`
LastPin discord.Timestamp `json:"timestamp,omitempty"`
}
// ChannelUnreadUpdateEvent is a dispatch event.
type ChannelUnreadUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
ChannelUnreadUpdates []struct {
ID discord.ChannelID `json:"id"`
LastMessageID discord.MessageID `json:"last_message_id"`
}
}
// ThreadCreateEvent is a dispatch event. It is sent when a thread is created,
// relevant to the current user, or when the current user is added to a thread.
type ThreadCreateEvent struct {
discord.Channel
}
// ThreadUpdateEvent is a dispatch event. It is sent when a thread is updated.
type ThreadUpdateEvent struct {
discord.Channel
}
// ThreadDeleteEvent is a dispatch event. It is sent when a thread relevant to
// the current user is deleted.
type ThreadDeleteEvent struct {
// ID is the id of this channel.
ID discord.ChannelID `json:"id"`
// GuildID is the id of the guild.
GuildID discord.GuildID `json:"guild_id,omitempty"`
// Type is the type of channel.
Type discord.ChannelType `json:"type,omitempty"`
// ParentID is the id of the text channel this thread was created.
ParentID discord.ChannelID `json:"parent_id,omitempty"`
}
// ThreadListSyncEvent is a dispatch event. It is sent when the current user
// gains access to a channel.
type ThreadListSyncEvent struct {
// GuildID is the id of the guild.
GuildID discord.GuildID `json:"guild_id"`
// ChannelIDs are the parent channel ids whose threads are being
// synced. If nil, then threads were synced for the entire guild.
// This slice may contain ChannelIDs that have no active threads as
// well, so you know to clear that data.
ChannelIDs []discord.ChannelID `json:"channel_ids,omitempty"`
Threads []discord.Channel `json:"threads"`
Members []discord.ThreadMember `json:"members"`
}
// ThreadMemberUpdateEvent is a dispatch event. It is sent when the thread
// member object for the current user is updated.
type ThreadMemberUpdateEvent struct {
discord.ThreadMember
}
// ThreadMembersUpdateEvent is a dispatch event. It is sent when anyone is added
// to or removed from a thread. If the current user does not have the
// GUILD_MEMBERS Gateway Intent, then this event will only be sent if the
// current user was added to or removed from the thread.
type ThreadMembersUpdateEvent struct {
// ID is the id of the thread.
ID discord.ChannelID `json:"id"`
// GuildID is the id of the guild.
GuildID discord.GuildID `json:"guild_id"`
// MemberCount is the approximate number of members in the thread,
// capped at 50.
MemberCount int `json:"member_count"`
// AddedMembers are the users who were added to the thread.
AddedMembers []discord.ThreadMember `json:"added_members,omitempty"`
// RemovedUserIDs are the ids of the users who were removed from the
// thread.
RemovedMemberIDs []discord.UserID `json:"removed_member_ids,omitempty"`
}
// GuildCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildCreateEvent struct {
discord.Guild
Joined discord.Timestamp `json:"joined_at,omitempty"`
Large bool `json:"large,omitempty"`
Unavailable bool `json:"unavailable,omitempty"`
MemberCount uint64 `json:"member_count,omitempty"`
VoiceStates []discord.VoiceState `json:"voice_states,omitempty"`
Members []discord.Member `json:"members,omitempty"`
Channels []discord.Channel `json:"channels,omitempty"`
Threads []discord.Channel `json:"threads,omitempty"`
Presences []discord.Presence `json:"presences,omitempty"`
}
// GuildUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildUpdateEvent struct {
discord.Guild
}
// GuildDeleteEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildDeleteEvent struct {
ID discord.GuildID `json:"id"`
// Unavailable if false == removed
Unavailable bool `json:"unavailable"`
}
// GuildAuditLogEntryCreateEvent is a dispatch event.
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildAuditLogEntryCreateEvent struct {
discord.AuditLogEntry
}
// GuildBanAddEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildBanAddEvent struct {
GuildID discord.GuildID `json:"guild_id"`
User discord.User `json:"user"`
}
// GuildBanRemoveEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildBanRemoveEvent struct {
GuildID discord.GuildID `json:"guild_id"`
User discord.User `json:"user"`
}
// GuildEmojisUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildEmojisUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
Emojis []discord.Emoji `json:"emojis"`
}
// GuildIntegrationsUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildIntegrationsUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
}
// GuildMemberAddEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildMemberAddEvent struct {
discord.Member
GuildID discord.GuildID `json:"guild_id"`
}
// GuildMemberRemoveEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildMemberRemoveEvent struct {
GuildID discord.GuildID `json:"guild_id"`
User discord.User `json:"user"`
}
// GuildMemberUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildMemberUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
RoleIDs []discord.RoleID `json:"roles"`
User discord.User `json:"user"`
Nick string `json:"nick"`
Avatar discord.Hash `json:"avatar"`
IsPending bool `json:"pending,omitempty"`
CommunicationDisabledUntil discord.Timestamp `json:"communication_disabled_until"`
}
// UpdateMember updates the given discord.Member.
func (u *GuildMemberUpdateEvent) UpdateMember(m *discord.Member) {
m.RoleIDs = u.RoleIDs
m.User = u.User
m.Nick = u.Nick
m.Avatar = u.Avatar
m.IsPending = u.IsPending
m.CommunicationDisabledUntil = u.CommunicationDisabledUntil
}
// GuildMembersChunkEvent is a dispatch event. It is sent when the Guild Request
// Members command is sent.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildMembersChunkEvent struct {
GuildID discord.GuildID `json:"guild_id"`
Members []discord.Member `json:"members"`
ChunkIndex int `json:"chunk_index"`
ChunkCount int `json:"chunk_count"`
// Whatever's not found goes here
NotFound []string `json:"not_found,omitempty"`
// Only filled if requested
Presences []discord.Presence `json:"presences,omitempty"`
Nonce string `json:"nonce,omitempty"`
}
// GuildMemberListUpdate is a dispatch event. It is an undocumented event. It's
// received when the client sends over GuildSubscriptions with the Channels
// field used. The State package does not handle this event.
type GuildMemberListUpdate struct {
ID string `json:"id"`
GuildID discord.GuildID `json:"guild_id"`
MemberCount uint64 `json:"member_count"`
OnlineCount uint64 `json:"online_count"`
// Groups is all the visible role sections.
Groups []GuildMemberListGroup `json:"groups"`
Ops []GuildMemberListOp `json:"ops"`
}
// GuildMemberListGroup is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildMemberListGroup struct {
ID string `json:"id"` // either discord.RoleID, "online" or "offline"
Count uint64 `json:"count"`
}
// GuildMemberListOp is an entry of every operation in GuildMemberListUpdate.
type GuildMemberListOp struct {
// Mysterious string, so far spotted to be [SYNC, INSERT, UPDATE, DELETE].
Op string `json:"op"`
// NON-SYNC ONLY
// Only available for Ops that aren't "SYNC".
Index int `json:"index,omitempty"`
Item GuildMemberListOpItem `json:"item,omitempty"`
// SYNC ONLY
// Range requested in GuildSubscribeCommand.
Range [2]int `json:"range,omitempty"`
// Items is basically a linear list of roles and members, similarly to
// how the client renders it. No, it's not nested.
Items []GuildMemberListOpItem `json:"items,omitempty"`
}
// GuildMemberListOpItem is a union of either Group or Member. Refer to
// (*GuildMemberListUpdate).Ops for more.
type GuildMemberListOpItem struct {
Group *GuildMemberListGroup `json:"group,omitempty"`
Member *struct {
discord.Member
HoistedRole string `json:"hoisted_role"`
Presence discord.Presence `json:"presence"`
} `json:"member,omitempty"`
}
// GuildRoleCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildRoleCreateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
Role discord.Role `json:"role"`
}
// GuildRoleUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildRoleUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
Role discord.Role `json:"role"`
}
// GuildRoleDeleteEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guilds
type GuildRoleDeleteEvent struct {
GuildID discord.GuildID `json:"guild_id"`
RoleID discord.RoleID `json:"role_id"`
}
// InviteCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#invites
type InviteCreateEvent struct {
Code string `json:"code"`
CreatedAt discord.Timestamp `json:"created_at"`
ChannelID discord.ChannelID `json:"channel_id"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
// Similar to discord.Invite
Inviter *discord.User `json:"inviter,omitempty"`
Target *discord.User `json:"target_user,omitempty"`
TargetType discord.InviteUserType `json:"target_user_type,omitempty"`
discord.InviteMetadata
}
// InviteDeleteEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#invites
type InviteDeleteEvent struct {
Code string `json:"code"`
ChannelID discord.ChannelID `json:"channel_id"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
}
// MessageCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageCreateEvent struct {
discord.Message
Member *discord.Member `json:"member,omitempty"`
}
// MessageUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageUpdateEvent struct {
discord.Message
Member *discord.Member `json:"member,omitempty"`
}
// MessageDeleteEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageDeleteEvent struct {
ID discord.MessageID `json:"id"`
ChannelID discord.ChannelID `json:"channel_id"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
}
// MessageDeleteBulkEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageDeleteBulkEvent struct {
IDs []discord.MessageID `json:"ids"`
ChannelID discord.ChannelID `json:"channel_id"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
}
// MessageReactionAddEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageReactionAddEvent struct {
UserID discord.UserID `json:"user_id"`
ChannelID discord.ChannelID `json:"channel_id"`
MessageID discord.MessageID `json:"message_id"`
Emoji discord.Emoji `json:"emoji,omitempty"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
Member *discord.Member `json:"member,omitempty"`
}
// MessageReactionRemoveEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageReactionRemoveEvent struct {
UserID discord.UserID `json:"user_id"`
ChannelID discord.ChannelID `json:"channel_id"`
MessageID discord.MessageID `json:"message_id"`
Emoji discord.Emoji `json:"emoji"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
}
// MessageReactionRemoveAllEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageReactionRemoveAllEvent struct {
ChannelID discord.ChannelID `json:"channel_id"`
MessageID discord.MessageID `json:"message_id"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
}
// MessageReactionRemoveEmojiEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#messages
type MessageReactionRemoveEmojiEvent struct {
ChannelID discord.ChannelID `json:"channel_id"`
MessageID discord.MessageID `json:"message_id"`
Emoji discord.Emoji `json:"emoji"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
}
// MessageAckEvent is a dispatch event.
type MessageAckEvent struct {
MessageID discord.MessageID `json:"message_id"`
ChannelID discord.ChannelID `json:"channel_id"`
}
// PresenceUpdateEvent is a dispatch event. It represents the structure of the
// Presence Update Event object.
//
// https://discord.com/developers/docs/topics/gateway#presence-update-presence-update-event-fields
type PresenceUpdateEvent struct {
discord.Presence
}
// PresencesReplaceEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#presence
type PresencesReplaceEvent []PresenceUpdateEvent
// SessionsReplaceEvent is a dispatch event. It is undocumented. It's likely
// used for current user's presence updates.
type SessionsReplaceEvent []UserSession
// TypingStartEvent is a dispatch event.
type TypingStartEvent struct {
ChannelID discord.ChannelID `json:"channel_id"`
UserID discord.UserID `json:"user_id"`
Timestamp discord.UnixTimestamp `json:"timestamp"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
Member *discord.Member `json:"member,omitempty"`
}
// UserUpdateEvent is a dispatch event.
type UserUpdateEvent struct {
discord.User
}
// VoiceStateUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#voice
type VoiceStateUpdateEvent struct {
discord.VoiceState
}
// VoiceServerUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#voice
type VoiceServerUpdateEvent struct {
Token string `json:"token"`
GuildID discord.GuildID `json:"guild_id"`
Endpoint string `json:"endpoint"`
}
// WebhooksUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#webhooks
type WebhooksUpdateEvent struct {
GuildID discord.GuildID `json:"guild_id"`
ChannelID discord.ChannelID `json:"channel_id"`
}
// InteractionCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#webhooks
type InteractionCreateEvent struct {
discord.InteractionEvent
}
// Undocumented
// UserGuildSettingsUpdateEvent is a dispatch event. It is undocumented.
type UserGuildSettingsUpdateEvent struct {
UserGuildSetting
}
// UserSettingsUpdateEvent is a dispatch event. It is undocumented.
type UserSettingsUpdateEvent struct {
UserSettings
}
// UserNoteUpdateEvent is a dispatch event. It is undocumented.
type UserNoteUpdateEvent struct {
ID discord.UserID `json:"id"`
Note string `json:"note"`
}
// RelationshipAddEvent is a dispatch event. It is undocumented.
type RelationshipAddEvent struct {
discord.Relationship
}
// RelationshipRemoveEvent is a dispatch event. It is undocumented.
type RelationshipRemoveEvent struct {
discord.Relationship
}
// ConversationSummaryUpdateEvent is a dispatch event. It is undocumented.
type ConversationSummaryUpdateEvent struct {
ChannelID discord.ChannelID `json:"channel_id"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
Summaries []ConversationSummary `json:"summaries"`
}
// ConversationSummary is a structure for ConversationSummaryUpdateEvent.
// It is undocumented.
type ConversationSummary struct {
Unsafe bool `json:"unsafe"`
// Topic is the topic of the conversation.
Topic string `json:"topic"`
// ShortSummary is a short summary of the conversation.
// It is in sentence form.
ShortSummary string `json:"summ_short"`
// People is a list of user IDs in the conversation.
People []discord.UserID `json:"people"`
// StartID is the ID of the first message in the conversation.
StartID discord.MessageID `json:"start_id"`
// EndID is the ID of the last message in the conversation.
EndID discord.MessageID `json:"end_id"`
// MessageIDs is a list of message IDs in the conversation.
MessageIDs []discord.MessageID `json:"message_ids"`
// ID is some kind of ID that identifies the conversation?
ID discord.Snowflake `json:"id"`
// Count is the number of messages in the conversation.
Count int `json:"count"`
}
// ReadyEvent is a dispatch event for READY.
//
// https://discord.com/developers/docs/topics/gateway#ready
type ReadyEvent struct {
Version int `json:"v"`
User discord.User `json:"user"`
SessionID string `json:"session_id"`
PrivateChannels []discord.Channel `json:"private_channels"`
Guilds []GuildCreateEvent `json:"guilds"`
Shard *Shard `json:"shard,omitempty"`
Application struct {
ID discord.AppID `json:"id"`
Flags discord.ApplicationFlags `json:"flags"`
} `json:"application"`
// Bot users need not concern with what's in here. This field is only
// unmarshaled, not marshaled.
ReadyEventExtras `json:"-"`
}
func (r *ReadyEvent) UnmarshalJSON(b []byte) error {
type raw ReadyEvent
if err := json.Unmarshal(b, (*raw)(r)); err != nil {
return err
}
// Optionally unmarshal ReadyEventExtras.
if !r.User.Bot {
r.ExtrasDecodeErrors = json.PartialUnmarshal(b, &r.ReadyEventExtras)
}
if ReadyEventKeepRaw {
r.ReadyEventExtras.RawEventBody = append([]byte(nil), b...)
}
return nil
}
// Ready subtypes.
type (
// ReadyEventExtras contains undocumented fields pertaining to the Ready
// event. This is the only event that receives this special treatment,
// because it's the one with the most undocumented things.
ReadyEventExtras struct {
UserSettings *UserSettings `json:"user_settings,omitempty"`
ReadStates []ReadState `json:"read_state,omitempty"`
UserGuildSettings []UserGuildSetting `json:"user_guild_settings,omitempty"`
Relationships []discord.Relationship `json:"relationships,omitempty"`
Presences []discord.Presence `json:"presences,omitempty"`
Sessions []UserSession `json:"sessions,omitempty"`
SessionID string `json:"session_id,omitempty"`
FriendSuggestionCount int `json:"friend_suggestion_count,omitempty"`
GeoOrderedRTCRegions []string `json:"geo_ordered_rtc_regions,omitempty"`
// RawEventBody is the raw JSON body for the Ready event. It is only
// available if ReadyEventKeepRaw is true.
RawEventBody json.Raw
// ExtrasDecodeErrors will be non-nil if there were errors decoding the
// ReadyEventExtras.
ExtrasDecodeErrors []error
}
// ReadState is a single ReadState entry. It is undocumented.
ReadState struct {
ChannelID discord.ChannelID `json:"id"`
LastMessageID discord.MessageID `json:"last_message_id"`
LastPinTimestamp discord.Timestamp `json:"last_pin_timestamp"`
MentionCount int `json:"mention_count"`
}
UserSession struct {
Status discord.Status `json:"status"`
SessionID string `json:"session_id"`
Activities []discord.Activity `json:"activities"`
ClientInfo struct {
Version int `json:"version"`
OS string `json:"os"`
Client string `json:"client"`
} `json:"client_info"`
Active bool `json:"active,omitempty"`
}
// UserSettings is the struct for (almost) all user settings. It is
// undocumented.
UserSettings struct {
ShowCurrentGame bool `json:"show_current_game"`
DefaultGuildsRestricted bool `json:"default_guilds_restricted"`
InlineAttachmentMedia bool `json:"inline_attachment_media"`
InlineEmbedMedia bool `json:"inline_embed_media"`
GIFAutoPlay bool `json:"gif_auto_play"`
RenderEmbeds bool `json:"render_embeds"`
RenderReactions bool `json:"render_reactions"`
AnimateEmoji bool `json:"animate_emoji"`
AnimateStickers int `json:"animate_stickers"`
EnableTTSCommand bool `json:"enable_tts_command"`
MessageDisplayCompact bool `json:"message_display_compact"`
ConvertEmoticons bool `json:"convert_emoticons"`
ExplicitContentFilter uint8 `json:"explicit_content_filter"` // ???
DisableGamesTab bool `json:"disable_games_tab"`
DeveloperMode bool `json:"developer_mode"`
DetectPlatformAccounts bool `json:"detect_platform_accounts"`
StreamNotification bool `json:"stream_notification_enabled"`
AccessibilityDetection bool `json:"allow_accessibility_detection"`
ContactSync bool `json:"contact_sync_enabled"`
NativePhoneIntegration bool `json:"native_phone_integration_enabled"`
TimezoneOffset int `json:"timezone_offset"`
Locale string `json:"locale"`
Theme string `json:"theme"`
GuildPositions []discord.GuildID `json:"guild_positions"`
GuildFolders []GuildFolder `json:"guild_folders"`
RestrictedGuilds []discord.GuildID `json:"restricted_guilds"`
FriendSourceFlags FriendSourceFlags `json:"friend_source_flags"`
Status discord.Status `json:"status"`
CustomStatus *CustomUserStatus `json:"custom_status"`
}
// CustomUserStatus is the custom user status that allows setting an emoji
// and a piece of text on each user.
CustomUserStatus struct {
Text string `json:"text"`
ExpiresAt discord.Timestamp `json:"expires_at,omitempty"`
EmojiID discord.EmojiID `json:"emoji_id,string"`
EmojiName string `json:"emoji_name"`
}
// UserGuildSetting stores the settings for a single guild. It is
// undocumented.
UserGuildSetting struct {
GuildID discord.GuildID `json:"guild_id"`
SuppressRoles bool `json:"suppress_roles"`
SuppressEveryone bool `json:"suppress_everyone"`
Muted bool `json:"muted"`
MuteConfig *UserMuteConfig `json:"mute_config"`
MobilePush bool `json:"mobile_push"`
Notifications UserNotification `json:"message_notifications"`
ChannelOverrides []UserChannelOverride `json:"channel_overrides"`
}
// A UserChannelOverride struct describes a channel settings override for a
// users guild settings.
UserChannelOverride struct {
Muted bool `json:"muted"`
MuteConfig *UserMuteConfig `json:"mute_config"`
Notifications UserNotification `json:"message_notifications"`
ChannelID discord.ChannelID `json:"channel_id"`
}
// UserMuteConfig seems to describe the mute settings. It belongs to the
// UserGuildSettingEntry and UserChannelOverride structs and is
// undocumented.
UserMuteConfig struct {
SelectedTimeWindow int `json:"selected_time_window"`
EndTime discord.Timestamp `json:"end_time"`
}
// GuildFolder holds a single folder that you see in the left guild panel.
GuildFolder struct {
Name string `json:"name"`
ID GuildFolderID `json:"id"`
GuildIDs []discord.GuildID `json:"guild_ids"`
Color discord.Color `json:"color"`
}
// FriendSourceFlags describes sources that friend requests could be sent
// from. It belongs to the UserSettings struct and is undocumented.
FriendSourceFlags struct {
All bool `json:"all,omitempty"`
MutualGuilds bool `json:"mutual_guilds,omitempty"`
MutualFriends bool `json:"mutual_friends,omitempty"`
}
)
// UserNotification is the notification setting for a channel or guild.
type UserNotification uint8
const (
AllNotifications UserNotification = iota
OnlyMentions
NoNotifications
GuildDefaults
)
// GuildFolderID is possibly a snowflake. It can also be 0 (null) or a low
// number of unknown significance.
type GuildFolderID int64
func (g *GuildFolderID) UnmarshalJSON(b []byte) error {
var body = string(b)
if body == "null" {
return nil
}
body = strings.Trim(body, `"`)
u, err := strconv.ParseInt(body, 10, 64)
if err != nil {
return err
}
*g = GuildFolderID(u)
return nil
}
func (g GuildFolderID) MarshalJSON() ([]byte, error) {
if g == 0 {
return []byte("null"), nil
}
return []byte(strconv.FormatInt(int64(g), 10)), nil
}
// ReadySupplementalEvent is a dispatch event for READY_SUPPLEMENTAL. It is an
// undocumented event. For now, this event is never used, and its usage have yet
// been discovered.
type ReadySupplementalEvent struct {
Guilds []GuildCreateEvent `json:"guilds"` // only have ID and VoiceStates
MergedMembers [][]SupplementalMember `json:"merged_members"`
MergedPresences MergedPresences `json:"merged_presences"`
}
// ReadySupplemental event structs.
type (
// SupplementalMember is the struct for a member in the MergedMembers field
// of ReadySupplementalEvent. It has slight differences to discord.Member.
SupplementalMember struct {
UserID discord.UserID `json:"user_id"`
Nick string `json:"nick,omitempty"`
RoleIDs []discord.RoleID `json:"roles"`
GuildID discord.GuildID `json:"guild_id,omitempty"`
IsPending bool `json:"pending,omitempty"`
HoistedRole discord.RoleID `json:"hoisted_role"`
Mute bool `json:"mute"`
Deaf bool `json:"deaf"`
// Joined specifies when the user joined the guild.
Joined discord.Timestamp `json:"joined_at"`
// BoostedSince specifies when the user started boosting the guild.
BoostedSince discord.Timestamp `json:"premium_since,omitempty"`
}
// MergedPresences is the struct for presences of guilds' members and
// friends. It is undocumented.
MergedPresences struct {
Guilds [][]SupplementalPresence `json:"guilds"`
Friends []SupplementalPresence `json:"friends"`
}
// SupplementalPresence is a single presence for either a guild member or
// friend. It is used in MergedPresences and is undocumented.
SupplementalPresence struct {
UserID discord.UserID `json:"user_id"`
// Status is either "idle", "dnd", "online", or "offline".
Status discord.Status `json:"status"`
// Activities are the user's current activities.
Activities []discord.Activity `json:"activities"`
// ClientStaus is the user's platform-dependent status.
ClientStatus discord.ClientStatus `json:"client_status"`
// LastModified is only present in Friends.
LastModified discord.UnixMsTimestamp `json:"last_modified,omitempty"`
}
)
// ConvertSupplementalMembers converts a SupplementalMember to a regular Member.
func ConvertSupplementalMembers(sms []SupplementalMember) []discord.Member {
members := make([]discord.Member, len(sms))
for i, sm := range sms {
members[i] = discord.Member{
User: discord.User{ID: sm.UserID},
Nick: sm.Nick,
RoleIDs: sm.RoleIDs,
Joined: sm.Joined,
BoostedSince: sm.BoostedSince,
Deaf: sm.Deaf,
Mute: sm.Mute,
IsPending: sm.IsPending,
}
}
return members
}
// ConvertSupplementalPresences converts a SupplementalPresence to a regular
// Presence with an empty GuildID.
func ConvertSupplementalPresences(sps []SupplementalPresence) []discord.Presence {
presences := make([]discord.Presence, len(sps))
for i, sp := range sps {
presences[i] = discord.Presence{
User: discord.User{ID: sp.UserID},
Status: sp.Status,
Activities: sp.Activities,
ClientStatus: sp.ClientStatus,
}
}
return presences
}
// GuildScheduledEventCreateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guild-scheduled-event-create
type GuildScheduledEventCreateEvent struct {
discord.GuildScheduledEvent
}
// GuildScheduledEventUpdateEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guild-scheduled-event-update
type GuildScheduledEventUpdateEvent struct {
discord.GuildScheduledEvent
}
// GuildScheduledEventDeleteEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guild-scheduled-event-delete
type GuildScheduledEventDeleteEvent struct {
discord.GuildScheduledEvent
}
// GuildScheduledEventUserAddEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guild-scheduled-event-user-add
type GuildScheduledEventUserAddEvent struct {
// EventID is the id of the scheduled event
EventID discord.EventID `json:"guild_scheduled_event_id"`
// UserID is the id of the user being added
UserID discord.UserID `json:"user_id"`
// GuildID is the id of where the scheduled event belongs
GuildID discord.GuildID `json:"guild_id"`
}
// GuildScheduledEventUserRemoveEvent is a dispatch event.
//
// https://discord.com/developers/docs/topics/gateway#guild-scheduled-event-user-remove
type GuildScheduledEventUserRemoveEvent struct {
// EventID is the id of the scheduled event
EventID discord.EventID `json:"guild_scheduled_event_id"`
// UserID is the id of the user being removed
UserID discord.UserID `json:"user_id"`
// GuildID is the id of where the scheduled event belongs
GuildID discord.GuildID `json:"guild_id"`
}