mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-11-14 08:15:55 +00:00
Gateway: Refactor, v8 user struct updates
This commit refactored several structures from package discord to be in package gateway. Those structures are mostly presence ones, which per official documentation has a lot more to do with the Gateway API than the REST API or anything else. This commit also renamed several global variables to have a more consistent and obvious name. As of v8, the user API has had a lot of minor and some major changes, especially regarding its Ready event API. The most significant change is the addition of the ReadySupplemental event as well as several changes to the Ready field itself. All of these changes above are breaking, and they have already broken the state package. These breaking changes will be addressed in other packages by the next commit.
This commit is contained in:
parent
0a8b24339b
commit
6ef093eb98
|
|
@ -299,35 +299,6 @@ func (r Role) Mention() string {
|
|||
return r.ID.Mention()
|
||||
}
|
||||
|
||||
// ClientStaus is the user's platform-dependent status.
|
||||
//
|
||||
// https://discord.com/developers/docs/topics/gateway#client-status-object
|
||||
type ClientStatus struct {
|
||||
// Desktop is the user's status set for an active desktop (Windows,
|
||||
// Linux, Mac) application session.
|
||||
Desktop Status `json:"desktop,omitempty"`
|
||||
// Mobile is the user's status set for an active mobile (iOS, Android)
|
||||
// application session.
|
||||
Mobile Status `json:"mobile,omitempty"`
|
||||
// Web is the user's status set for an active web (browser, bot
|
||||
// account) application session.
|
||||
Web Status `json:"web,omitempty"`
|
||||
}
|
||||
|
||||
// https://discord.com/developers/docs/topics/gateway#presence-update
|
||||
type Presence struct {
|
||||
// User is the user presence is being updated for.
|
||||
User User `json:"user"`
|
||||
// GuildID is the id of the guild
|
||||
GuildID GuildID `json:"guild_id"`
|
||||
// Status is either "idle", "dnd", "online", or "offline".
|
||||
Status Status `json:"status"`
|
||||
// Activities are the user's current activities.
|
||||
Activities []Activity `json:"activities"`
|
||||
// ClientStaus is the user's platform-dependent status.
|
||||
ClientStatus ClientStatus `json:"client_status"`
|
||||
}
|
||||
|
||||
// https://discord.com/developers/docs/resources/guild#guild-member-object
|
||||
//
|
||||
// The field user won't be included in the member object attached to
|
||||
|
|
|
|||
|
|
@ -115,17 +115,6 @@ const (
|
|||
ConnectionVisibleEveryone
|
||||
)
|
||||
|
||||
type Status string
|
||||
|
||||
const (
|
||||
UnknownStatus Status = ""
|
||||
OnlineStatus Status = "online"
|
||||
DoNotDisturbStatus Status = "dnd"
|
||||
IdleStatus Status = "idle"
|
||||
InvisibleStatus Status = "invisible"
|
||||
OfflineStatus Status = "offline"
|
||||
)
|
||||
|
||||
type Activity struct {
|
||||
Name string `json:"name"`
|
||||
URL URL `json:"url,omitempty"`
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
// Identify structure is at identify.go
|
||||
|
||||
// Identify sends off the Identify command with the Gateway's IdentifyData.
|
||||
func (g *Gateway) Identify() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), g.WSTimeout)
|
||||
defer cancel()
|
||||
|
|
@ -18,10 +19,9 @@ func (g *Gateway) Identify() error {
|
|||
return g.IdentifyCtx(ctx)
|
||||
}
|
||||
|
||||
// IdentifyCtx sends off the Identify command with the Gateway's IdentifyData
|
||||
// with the given context for time out.
|
||||
func (g *Gateway) IdentifyCtx(ctx context.Context) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, g.WSTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := g.Identifier.Wait(ctx); err != nil {
|
||||
return errors.Wrap(err, "can't wait for identify()")
|
||||
}
|
||||
|
|
@ -114,20 +114,20 @@ func (g *Gateway) UpdateVoiceState(data UpdateVoiceStateData) error {
|
|||
return g.UpdateVoiceStateCtx(ctx, data)
|
||||
}
|
||||
|
||||
func (g *Gateway) UpdateVoiceStateCtx(
|
||||
ctx context.Context, data UpdateVoiceStateData) error {
|
||||
|
||||
func (g *Gateway) UpdateVoiceStateCtx(ctx context.Context, data UpdateVoiceStateData) error {
|
||||
return g.SendCtx(ctx, VoiceStateUpdateOP, data)
|
||||
}
|
||||
|
||||
// UpdateStatusData is sent by this client to indicate a presence or status
|
||||
// update.
|
||||
type UpdateStatusData struct {
|
||||
Since discord.UnixMsTimestamp `json:"since"` // 0 if not idle
|
||||
|
||||
// Both fields are nullable.
|
||||
// Activities can either be null, an empty slice, or be omitted.
|
||||
Activities *[]discord.Activity `json:"activities,omitempty"`
|
||||
|
||||
Status discord.Status `json:"status"`
|
||||
AFK bool `json:"afk"`
|
||||
Status Status `json:"status"`
|
||||
AFK bool `json:"afk"`
|
||||
}
|
||||
|
||||
func (g *Gateway) UpdateStatus(data UpdateStatusData) error {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ type (
|
|||
VoiceStates []discord.VoiceState `json:"voice_states,omitempty"`
|
||||
Members []discord.Member `json:"members,omitempty"`
|
||||
Channels []discord.Channel `json:"channels,omitempty"`
|
||||
Presences []discord.Presence `json:"presences,omitempty"`
|
||||
Presences []Presence `json:"presences,omitempty"`
|
||||
}
|
||||
GuildUpdateEvent struct {
|
||||
discord.Guild
|
||||
|
|
@ -114,7 +114,7 @@ type (
|
|||
NotFound []string `json:"not_found,omitempty"`
|
||||
|
||||
// Only filled if requested
|
||||
Presences []discord.Presence `json:"presences,omitempty"`
|
||||
Presences []Presence `json:"presences,omitempty"`
|
||||
Nonce string `json:"nonce,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ type (
|
|||
Member *struct {
|
||||
discord.Member
|
||||
HoistedRole string `json:"hoisted_role"`
|
||||
Presence discord.Presence `json:"presence"`
|
||||
Presence Presence `json:"presence"`
|
||||
} `json:"member,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -261,19 +261,67 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
// Status is the enumerate type for a user's status.
|
||||
type Status string
|
||||
|
||||
const (
|
||||
UnknownStatus Status = ""
|
||||
OnlineStatus Status = "online"
|
||||
DoNotDisturbStatus Status = "dnd"
|
||||
IdleStatus Status = "idle"
|
||||
InvisibleStatus Status = "invisible"
|
||||
OfflineStatus Status = "offline"
|
||||
)
|
||||
|
||||
// https://discord.com/developers/docs/topics/gateway#presence
|
||||
type (
|
||||
// Clients may only update their game status 5 times per 20 seconds.
|
||||
PresenceUpdateEvent struct {
|
||||
discord.Presence
|
||||
// Presence represents a partial Presence structure used by other structs to be
|
||||
// easily embedded. It does not contain any ID to identify who it belongs
|
||||
// to. For more information, refer to the PresenceUpdateEvent struct.
|
||||
Presence struct {
|
||||
// Status is either "idle", "dnd", "online", or "offline".
|
||||
Status Status `json:"status"`
|
||||
// Activities are the user's current activities.
|
||||
Activities []discord.Activity `json:"activities"`
|
||||
// ClientStaus is the user's platform-dependent status.
|
||||
ClientStatus ClientStatus `json:"client_status"`
|
||||
}
|
||||
PresencesReplaceEvent []discord.Presence
|
||||
|
||||
// ClientStaus is the user's platform-dependent status.
|
||||
//
|
||||
// https://discord.com/developers/docs/topics/gateway#client-status-object
|
||||
ClientStatus struct {
|
||||
// Desktop is the user's status set for an active desktop (Windows,
|
||||
// Linux, Mac) application session.
|
||||
Desktop Status `json:"desktop,omitempty"`
|
||||
// Mobile is the user's status set for an active mobile (iOS, Android)
|
||||
// application session.
|
||||
Mobile Status `json:"mobile,omitempty"`
|
||||
// Web is the user's status set for an active web (browser, bot
|
||||
// account) application session.
|
||||
Web Status `json:"web,omitempty"`
|
||||
}
|
||||
|
||||
// PresenceUpdateEvent represents the structure of the Presence Update Event
|
||||
// object. This event may be sent on itself or within other events.
|
||||
//
|
||||
// https://discord.com/developers/docs/topics/gateway#presence-update-presence-update-event-fields
|
||||
PresenceUpdateEvent struct {
|
||||
// User is the user presence is being updated for.
|
||||
User discord.User `json:"user"`
|
||||
// GuildID is the id of the guild
|
||||
GuildID discord.GuildID `json:"guild_id"`
|
||||
// Presence contains the rest of the update struct.
|
||||
Presence
|
||||
}
|
||||
|
||||
PresencesReplaceEvent []PresenceUpdateEvent
|
||||
|
||||
// SessionsReplaceEvent is an undocumented user event. It's likely used for
|
||||
// current user's presence updates.
|
||||
SessionsReplaceEvent []struct {
|
||||
Status discord.Status `json:"status"`
|
||||
SessionID string `json:"session_id"`
|
||||
Status Status `json:"status"`
|
||||
SessionID string `json:"session_id"`
|
||||
|
||||
Activities []discord.Activity `json:"activities"`
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ type Event = interface{}
|
|||
|
||||
// EventCreator maps an event type string to a constructor.
|
||||
var EventCreator = map[string]func() Event{
|
||||
"HELLO": func() Event { return new(HelloEvent) },
|
||||
"READY": func() Event { return new(ReadyEvent) },
|
||||
"RESUMED": func() Event { return new(ResumedEvent) },
|
||||
"INVALID_SESSION": func() Event { return new(InvalidSessionEvent) },
|
||||
"HELLO": func() Event { return new(HelloEvent) },
|
||||
"READY": func() Event { return new(ReadyEvent) },
|
||||
"READY_SUPPLEMENTAL": func() Event { return new(ReadySupplementalEvent) },
|
||||
"RESUMED": func() Event { return new(ResumedEvent) },
|
||||
"INVALID_SESSION": func() Event { return new(InvalidSessionEvent) },
|
||||
|
||||
"CHANNEL_CREATE": func() Event { return new(ChannelCreateEvent) },
|
||||
"CHANNEL_UPDATE": func() Event { return new(ChannelUpdateEvent) },
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
"github.com/diamondburned/arikawa/v2/api"
|
||||
"github.com/diamondburned/arikawa/v2/discord"
|
||||
"github.com/diamondburned/arikawa/v2/internal/moreatomic"
|
||||
"github.com/diamondburned/arikawa/v2/utils/httputil"
|
||||
"github.com/diamondburned/arikawa/v2/utils/json"
|
||||
"github.com/diamondburned/arikawa/v2/utils/wsutil"
|
||||
|
|
@ -76,7 +77,11 @@ func BotURL(token string) (*BotData, error) {
|
|||
}
|
||||
|
||||
type Gateway struct {
|
||||
WS *wsutil.Websocket
|
||||
WS *wsutil.Websocket
|
||||
|
||||
// WSTimeout is a timeout for an arbitrary action. An example of this is the
|
||||
// timeout for Start and the timeout for sending each Gateway command
|
||||
// independently.
|
||||
WSTimeout time.Duration
|
||||
// ReconnectTimeout is the timeout used during reconnection.
|
||||
// If the a connection to the gateway can't be established before the
|
||||
|
|
@ -96,7 +101,7 @@ type Gateway struct {
|
|||
SessionID string
|
||||
|
||||
Identifier *Identifier
|
||||
Sequence *Sequence
|
||||
Sequence *moreatomic.Int64
|
||||
|
||||
PacerLoop wsutil.PacemakerLoop
|
||||
|
||||
|
|
@ -162,7 +167,7 @@ func NewCustomGateway(gatewayURL, token string) *Gateway {
|
|||
|
||||
Events: make(chan Event, wsutil.WSBuffer),
|
||||
Identifier: DefaultIdentifier(token),
|
||||
Sequence: NewSequence(),
|
||||
Sequence: moreatomic.NewInt64(0),
|
||||
|
||||
ErrorLog: wsutil.WSError,
|
||||
AfterClose: func(error) {},
|
||||
|
|
|
|||
|
|
@ -9,15 +9,105 @@ import (
|
|||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
// Identity is used as the default identity when initializing a new Gateway.
|
||||
var Identity = IdentifyProperties{
|
||||
// DefaultPresence is used as the default presence when initializing a new
|
||||
// Gateway.
|
||||
var DefaultPresence *UpdateStatusData
|
||||
|
||||
// Identifier is a wrapper around IdentifyData to add in appropriate rate
|
||||
// limiters.
|
||||
type Identifier struct {
|
||||
IdentifyData
|
||||
|
||||
IdentifyShortLimit *rate.Limiter // optional
|
||||
IdentifyGlobalLimit *rate.Limiter // optional
|
||||
}
|
||||
|
||||
// DefaultIdentifier creates a new default Identifier
|
||||
func DefaultIdentifier(token string) *Identifier {
|
||||
return NewIdentifier(IdentifyData{
|
||||
Token: token,
|
||||
Properties: DefaultIdentity,
|
||||
Shard: DefaultShard,
|
||||
Presence: DefaultPresence,
|
||||
|
||||
Compress: true,
|
||||
LargeThreshold: 50,
|
||||
})
|
||||
}
|
||||
|
||||
// NewIdentifier creates a new identifier with the given IdentifyData and
|
||||
// default rate limiters.
|
||||
func NewIdentifier(data IdentifyData) *Identifier {
|
||||
return &Identifier{
|
||||
IdentifyData: data,
|
||||
IdentifyShortLimit: rate.NewLimiter(rate.Every(5*time.Second), 1),
|
||||
IdentifyGlobalLimit: rate.NewLimiter(rate.Every(24*time.Hour), 1000),
|
||||
}
|
||||
}
|
||||
|
||||
// Wait waits for the rate limiters to pass. If a limiter is nil, then it will
|
||||
// not be used to wait. This is useful
|
||||
func (i *Identifier) Wait(ctx context.Context) error {
|
||||
if i.IdentifyShortLimit != nil {
|
||||
if err := i.IdentifyShortLimit.Wait(ctx); err != nil {
|
||||
return errors.Wrap(err, "can't wait for short limit")
|
||||
}
|
||||
}
|
||||
|
||||
if i.IdentifyGlobalLimit != nil {
|
||||
if err := i.IdentifyGlobalLimit.Wait(ctx); err != nil {
|
||||
return errors.Wrap(err, "can't wait for global limit")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultIdentity is used as the default identity when initializing a new
|
||||
// Gateway.
|
||||
var DefaultIdentity = IdentifyProperties{
|
||||
OS: runtime.GOOS,
|
||||
Browser: "Arikawa",
|
||||
Device: "Arikawa",
|
||||
}
|
||||
|
||||
// Presence is used as the default presence when initializing a new Gateway.
|
||||
var Presence *UpdateStatusData
|
||||
// IdentifyData is the struct for a data that's sent over in an Identify
|
||||
// command.
|
||||
type IdentifyData struct {
|
||||
Token string `json:"token"`
|
||||
Properties IdentifyProperties `json:"properties"`
|
||||
|
||||
Compress bool `json:"compress,omitempty"` // true
|
||||
LargeThreshold uint `json:"large_threshold,omitempty"` // 50
|
||||
|
||||
Shard *Shard `json:"shard,omitempty"` // [ shard_id, num_shards ]
|
||||
|
||||
Presence *UpdateStatusData `json:"presence,omitempty"`
|
||||
|
||||
Intents Intents `json:"intents,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultIdentifyData creates a default IdentifyData with the given token.
|
||||
func DefaultIdentifyData(token string) IdentifyData {
|
||||
return IdentifyData{
|
||||
Token: token,
|
||||
Properties: DefaultIdentity,
|
||||
Shard: DefaultShard,
|
||||
Presence: DefaultPresence,
|
||||
|
||||
Compress: true,
|
||||
LargeThreshold: 50,
|
||||
}
|
||||
}
|
||||
|
||||
// SetShard is a helper function to set the shard configuration inside
|
||||
// IdentifyData.
|
||||
func (i *IdentifyData) SetShard(id, num int) {
|
||||
if i.Shard == nil {
|
||||
i.Shard = new(Shard)
|
||||
}
|
||||
i.Shard[0], i.Shard[1] = id, num
|
||||
}
|
||||
|
||||
type IdentifyProperties struct {
|
||||
// Required
|
||||
|
|
@ -33,60 +123,22 @@ type IdentifyProperties struct {
|
|||
ReferringDomain string `json:"referring_domain,omitempty"`
|
||||
}
|
||||
|
||||
type IdentifyData struct {
|
||||
Token string `json:"token"`
|
||||
Properties IdentifyProperties `json:"properties"`
|
||||
// Shard is a type for two numbers that represent the Bot's shard configuration.
|
||||
// The first number is the shard's ID, which could be obtained through the
|
||||
// ShardID method. The second number is the total number of shards, which could
|
||||
// be obtained through the NumShards method.
|
||||
type Shard [2]int
|
||||
|
||||
Compress bool `json:"compress,omitempty"` // true
|
||||
LargeThreshold uint `json:"large_threshold,omitempty"` // 50
|
||||
// DefaultShard returns the default shard configuration of 1 shard total, in
|
||||
// which the current shard ID is 0.
|
||||
var DefaultShard = &Shard{0, 1}
|
||||
|
||||
Shard *Shard `json:"shard,omitempty"` // [ shard_id, num_shards ]
|
||||
|
||||
Presence *UpdateStatusData `json:"presence,omitempty"`
|
||||
|
||||
Intents Intents `json:"intents,omitempty"`
|
||||
// ShardID returns the current shard's ID. It uses the first number.
|
||||
func (s Shard) ShardID() int {
|
||||
return s[0]
|
||||
}
|
||||
|
||||
func (i *IdentifyData) SetShard(id, num int) {
|
||||
if i.Shard == nil {
|
||||
i.Shard = new(Shard)
|
||||
}
|
||||
i.Shard[0], i.Shard[1] = id, num
|
||||
}
|
||||
|
||||
type Identifier struct {
|
||||
IdentifyData
|
||||
|
||||
IdentifyShortLimit *rate.Limiter `json:"-"`
|
||||
IdentifyGlobalLimit *rate.Limiter `json:"-"`
|
||||
}
|
||||
|
||||
func DefaultIdentifier(token string) *Identifier {
|
||||
return NewIdentifier(IdentifyData{
|
||||
Token: token,
|
||||
Properties: Identity,
|
||||
Shard: DefaultShard(),
|
||||
Presence: Presence,
|
||||
|
||||
Compress: true,
|
||||
LargeThreshold: 50,
|
||||
})
|
||||
}
|
||||
|
||||
func NewIdentifier(data IdentifyData) *Identifier {
|
||||
return &Identifier{
|
||||
IdentifyData: data,
|
||||
IdentifyShortLimit: rate.NewLimiter(rate.Every(5*time.Second), 1),
|
||||
IdentifyGlobalLimit: rate.NewLimiter(rate.Every(24*time.Hour), 1000),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Identifier) Wait(ctx context.Context) error {
|
||||
if err := i.IdentifyShortLimit.Wait(ctx); err != nil {
|
||||
return errors.Wrap(err, "can't wait for short limit")
|
||||
}
|
||||
if err := i.IdentifyGlobalLimit.Wait(ctx); err != nil {
|
||||
return errors.Wrap(err, "can't wait for global limit")
|
||||
}
|
||||
return nil
|
||||
// NumShards returns the total number of shards. It uses the second number.
|
||||
func (s Shard) NumShards() int {
|
||||
return s[1]
|
||||
}
|
||||
|
|
|
|||
257
gateway/ready.go
257
gateway/ready.go
|
|
@ -7,83 +7,169 @@ import (
|
|||
"github.com/diamondburned/arikawa/v2/discord"
|
||||
)
|
||||
|
||||
type ReadyEvent struct {
|
||||
Version int `json:"version"`
|
||||
type (
|
||||
// ReadyEvent is the struct for a READY event.
|
||||
ReadyEvent struct {
|
||||
Version int `json:"version"`
|
||||
|
||||
User discord.User `json:"user"`
|
||||
SessionID string `json:"session_id"`
|
||||
User discord.User `json:"user"`
|
||||
SessionID string `json:"session_id"`
|
||||
|
||||
PrivateChannels []discord.Channel `json:"private_channels"`
|
||||
Guilds []GuildCreateEvent `json:"guilds"`
|
||||
PrivateChannels []discord.Channel `json:"private_channels"`
|
||||
Guilds []GuildCreateEvent `json:"guilds"`
|
||||
|
||||
Shard *Shard `json:"shard"`
|
||||
Shard *Shard `json:"shard,omitempty"`
|
||||
|
||||
// Undocumented fields
|
||||
Settings *UserSettings `json:"user_settings,omitempty"`
|
||||
UserGuildSettings []UserGuildSettings `json:"user_guild_settings,omitempty"`
|
||||
// Undocumented fields
|
||||
|
||||
ReadState []ReadState `json:"read_state,omitempty"`
|
||||
Presences []discord.Presence `json:"presences,omitempty"`
|
||||
ReadStates *ReadStates `json:"read_state,omitempty"`
|
||||
UserSettings *UserSettings `json:"user_settings,omitempty"`
|
||||
UserGuildSettings *UserGuildSettings `json:"user_guild_settings,omitempty"`
|
||||
Relationships []discord.Relationship `json:"relationships,omitempty"`
|
||||
MergedMembers [][]SupplementalMember `json:"merged_members,omitempty"`
|
||||
|
||||
Relationships []discord.Relationship `json:"relationships,omitempty"`
|
||||
Notes map[discord.UserID]string `json:"notes,omitempty"`
|
||||
}
|
||||
FriendSuggestionCount int `json:"friend_suggestion_count,omitempty"`
|
||||
GeoOrderedRTCRegions []string `json:"geo_ordered_rtc_regions,omitempty"`
|
||||
}
|
||||
|
||||
type 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"`
|
||||
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"`
|
||||
// ReadStates is a struct that contains read state entries. It is an
|
||||
// undocumented Discord v8 API.
|
||||
ReadStates struct {
|
||||
Version int `json:"version"`
|
||||
Partial bool `json:"partial"`
|
||||
Entries []ReadState `json:"entries"`
|
||||
}
|
||||
|
||||
Locale string `json:"locale"`
|
||||
Theme string `json:"theme"`
|
||||
// ReadState is a single ReadState entry.
|
||||
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"`
|
||||
}
|
||||
|
||||
GuildPositions []discord.GuildID `json:"guild_positions"`
|
||||
GuildFolders []GuildFolder `json:"guild_folders"`
|
||||
RestrictedGuilds []discord.GuildID `json:"restricted_guilds"`
|
||||
// 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"`
|
||||
|
||||
FriendSourceFlags struct {
|
||||
All bool `json:"all"`
|
||||
MutualGuilds bool `json:"mutual_guilds"`
|
||||
MutualFriends bool `json:"mutual_friends"`
|
||||
} `json:"friend_source_flags"`
|
||||
Locale string `json:"locale"`
|
||||
Theme string `json:"theme"`
|
||||
|
||||
Status discord.Status `json:"status"`
|
||||
CustomStatus struct {
|
||||
GuildPositions []discord.GuildID `json:"guild_positions"`
|
||||
GuildFolders []GuildFolder `json:"guild_folders"`
|
||||
RestrictedGuilds []discord.GuildID `json:"restricted_guilds"`
|
||||
|
||||
FriendSourceFlags FriendSourceFlags `json:"friend_source_flags"`
|
||||
|
||||
Status 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"`
|
||||
} `json:"custom_status"`
|
||||
}
|
||||
}
|
||||
|
||||
// A UserGuildSettings stores data for a users guild settings.
|
||||
type UserGuildSettings struct {
|
||||
GuildID discord.GuildID `json:"guild_id"`
|
||||
// UserGuildSettings stores the settings for all user guilds. It is
|
||||
// undocumented.
|
||||
UserGuildSettings struct {
|
||||
Version int `json:"version"`
|
||||
Partial bool `json:"partial"`
|
||||
Entries []UserGuildSettingEntry `json:"entries"`
|
||||
}
|
||||
|
||||
SuppressEveryone bool `json:"suppress_everyone"`
|
||||
SuppressRoles bool `json:"suppress_roles"`
|
||||
Muted bool `json:"muted"`
|
||||
MobilePush bool `json:"mobile_push"`
|
||||
// UserGuildSettingEntry stores the settings for a single guild. It is
|
||||
// undocumented.
|
||||
UserGuildSettingEntry struct {
|
||||
Version int `json:"version"`
|
||||
|
||||
MessageNotifications UserNotification `json:"message_notifications"`
|
||||
ChannelOverrides []SettingsChannelOverride `json:"channel_overrides"`
|
||||
}
|
||||
GuildID discord.GuildID `json:"guild_id"`
|
||||
|
||||
SuppressRoles bool `json:"suppress_roles"`
|
||||
SuppressEveryone bool `json:"suppress_everyone"`
|
||||
Muted bool `json:"muted"`
|
||||
MuteConfig *UserGuildMute `json:"mute_config"`
|
||||
|
||||
MobilePush bool `json:"mobile_push"`
|
||||
MessageNotifications UserNotification `json:"message_notifications"`
|
||||
|
||||
ChannelOverrides []UserChannelOverride `json:"channel_overrides"`
|
||||
}
|
||||
|
||||
// UserGuildMute seems to describe the mute settings of a guild. It belongs
|
||||
// to the UserGuildSettingEntry struct and is undocumented.
|
||||
UserGuildMute struct {
|
||||
SelectedTimeWindow int `json:"selected_time_window"`
|
||||
EndTime discord.Timestamp `json:"end_time"`
|
||||
}
|
||||
|
||||
// A UserChannelOverride struct describes a channel settings override for a
|
||||
// users guild settings.
|
||||
UserChannelOverride struct {
|
||||
Muted bool `json:"muted"`
|
||||
|
||||
MessageNotifications UserNotification `json:"message_notifications"`
|
||||
ChannelID discord.ChannelID `json:"channel_id"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
RoleIDs []discord.RoleID `json:"roles"`
|
||||
|
||||
JoinedAt discord.Timestamp `json:"joined_at"`
|
||||
HoistedRole discord.RoleID `json:"hoisted_role"`
|
||||
|
||||
Mute bool `json:"mute"`
|
||||
Deaf bool `json:"deaf"`
|
||||
|
||||
Nick string `json:"nick,omitempty"`
|
||||
GuildID discord.GuildID `json:"guild_id,omitempty"`
|
||||
IsPending bool `json:"is_pending,omitempty"`
|
||||
PremiumSince discord.Timestamp `json:"premium_since,omitempty"`
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
@ -95,29 +181,6 @@ const (
|
|||
GuildDefaults
|
||||
)
|
||||
|
||||
type ReadState struct {
|
||||
ChannelID discord.ChannelID `json:"id"`
|
||||
LastMessageID discord.MessageID `json:"last_message_id"`
|
||||
MentionCount int `json:"mention_count"`
|
||||
}
|
||||
|
||||
// A UserGuildSettingsChannelOverride stores data for a channel override for a
|
||||
// users guild settings.
|
||||
type SettingsChannelOverride struct {
|
||||
Muted bool `json:"muted"`
|
||||
|
||||
MessageNotifications UserNotification `json:"message_notifications"`
|
||||
ChannelID discord.ChannelID `json:"channel_id"`
|
||||
}
|
||||
|
||||
// GuildFolder holds a single folder that you see in the left guild panel.
|
||||
type GuildFolder struct {
|
||||
Name string `json:"name"`
|
||||
ID GuildFolderID `json:"id"`
|
||||
GuildIDs []discord.GuildID `json:"guild_ids"`
|
||||
Color discord.Color `json:"color"`
|
||||
}
|
||||
|
||||
// GuildFolderID is possibly a snowflake. It can also be 0 (null) or a low
|
||||
// number of unknown significance.
|
||||
type GuildFolderID int64
|
||||
|
|
@ -146,3 +209,33 @@ func (g GuildFolderID) MarshalJSON() ([]byte, error) {
|
|||
|
||||
return []byte(strconv.FormatInt(int64(g), 10)), nil
|
||||
}
|
||||
|
||||
// ReadySupplemental event structs.
|
||||
type (
|
||||
// ReadySupplementalEvent is the struct for a READY_SUPPLEMENTAL event,
|
||||
// which is an undocumented event.
|
||||
ReadySupplementalEvent struct {
|
||||
Guilds []discord.Guild `json:"guilds"` // only have ID and VoiceStates
|
||||
MergedMembers [][]SupplementalMember `json:"merged_members"`
|
||||
MergedPresences MergedPresences `json:"merged_presences"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
|
||||
// Presence contains the rest of this struct.
|
||||
Presence
|
||||
|
||||
// LastModified is only present in Friends.
|
||||
LastModified discord.UnixMsTimestamp `json:"last_modified,omitempty"`
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
package gateway
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type Sequence int64
|
||||
|
||||
func NewSequence() *Sequence {
|
||||
return (*Sequence)(new(int64))
|
||||
}
|
||||
|
||||
func (s *Sequence) Set(seq int64) { atomic.StoreInt64((*int64)(s), seq) }
|
||||
func (s *Sequence) Get() int64 { return atomic.LoadInt64((*int64)(s)) }
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package gateway
|
||||
|
||||
type Shard [2]int
|
||||
|
||||
func DefaultShard() *Shard {
|
||||
var s = Shard([2]int{0, 1})
|
||||
return &s
|
||||
}
|
||||
|
||||
func (s Shard) ShardID() int {
|
||||
return s[0]
|
||||
}
|
||||
|
||||
func (s Shard) NumShards() int {
|
||||
return s[1]
|
||||
}
|
||||
14
internal/moreatomic/int.go
Normal file
14
internal/moreatomic/int.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package moreatomic
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type Int64 int64
|
||||
|
||||
func NewInt64(v int64) *Int64 {
|
||||
i := new(Int64)
|
||||
*i = Int64(v)
|
||||
return i
|
||||
}
|
||||
|
||||
func (i *Int64) Set(v int64) { atomic.StoreInt64((*int64)(i), v) }
|
||||
func (i *Int64) Get() int64 { return atomic.LoadInt64((*int64)(i)) }
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package moreatomic
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type Serial struct {
|
||||
serial uint32
|
||||
}
|
||||
|
||||
func (s *Serial) Get() int {
|
||||
return int(atomic.LoadUint32(&s.serial))
|
||||
}
|
||||
|
||||
func (s *Serial) Incr() int {
|
||||
atomic.AddUint32(&s.serial, 1)
|
||||
return s.Get()
|
||||
}
|
||||
Loading…
Reference in a new issue