Merge pull request #728 from bwmarrin/feature-ExposeIdentify

Expose Identify Packet
This commit is contained in:
bwmarrin 2020-01-24 17:20:51 -06:00 committed by GitHub
commit d4610f32c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 40 deletions

View file

@ -17,6 +17,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"runtime"
"time" "time"
) )
@ -63,6 +64,14 @@ func New(args ...interface{}) (s *Session, err error) {
LastHeartbeatAck: time.Now().UTC(), LastHeartbeatAck: time.Now().UTC(),
} }
// Initilize the Identify Package with defaults
// These can be modified prior to calling Open()
s.Identify.Compress = true
s.Identify.LargeThreshold = 250
s.Identify.GuildSubscriptions = true
s.Identify.Properties.OS = runtime.GOOS
s.Identify.Properties.Browser = "DiscordGo v" + VERSION
// If no arguments are passed return the empty Session interface. // If no arguments are passed return the empty Session interface.
if args == nil { if args == nil {
return return
@ -94,7 +103,8 @@ func New(args ...interface{}) (s *Session, err error) {
// If third string exists, it must be an auth token. // If third string exists, it must be an auth token.
if len(v) > 2 { if len(v) > 2 {
s.Token = v[2] s.Identify.Token = v[2]
s.Token = v[2] // TODO: Remove, Deprecated - Kept for backwards compatibility.
} }
case string: case string:
@ -107,7 +117,8 @@ func New(args ...interface{}) (s *Session, err error) {
} else if pass == "" { } else if pass == "" {
pass = v pass = v
} else if s.Token == "" { } else if s.Token == "" {
s.Token = v s.Identify.Token = v
s.Token = v // TODO: Remove, Deprecated - Kept for backwards compatibility.
} else { } else {
err = fmt.Errorf("too many string parameters provided") err = fmt.Errorf("too many string parameters provided")
return return
@ -127,10 +138,12 @@ func New(args ...interface{}) (s *Session, err error) {
// Discord will verify it for free, or log the user in if it is // Discord will verify it for free, or log the user in if it is
// invalid. // invalid.
if pass == "" { if pass == "" {
s.Token = auth s.Identify.Token = auth
s.Token = auth // TODO: Remove, Deprecated - Kept for backwards compatibility.
} else { } else {
err = s.Login(auth, pass) err = s.Login(auth, pass)
if err != nil || s.Token == "" { // TODO: Remove last s.Token part, Deprecated - Kept for backwards compatibility.
if err != nil || s.Identify.Token == "" || s.Token == "" {
if s.MFA { if s.MFA {
err = ErrMFA err = ErrMFA
} else { } else {
@ -140,8 +153,5 @@ func New(args ...interface{}) (s *Session, err error) {
} }
} }
// The Session is now able to have RestAPI methods called on it.
// It is recommended that you now call Open() so that events will trigger.
return return
} }

View file

@ -29,8 +29,10 @@ type Session struct {
// General configurable settings. // General configurable settings.
// Authentication token for this session // Authentication token for this session
// TODO: Remove Below, Deprecated, Use Identify struct
Token string Token string
MFA bool
MFA bool
// Debug for printing JSON request/responses // Debug for printing JSON request/responses
Debug bool // Deprecated, will be removed. Debug bool // Deprecated, will be removed.
@ -39,6 +41,11 @@ type Session struct {
// Should the session reconnect the websocket on errors. // Should the session reconnect the websocket on errors.
ShouldReconnectOnError bool ShouldReconnectOnError bool
// Identify is sent during initial handshake with the discord gateway.
// https://discordapp.com/developers/docs/topics/gateway#identify
Identify Identify
// TODO: Remove Below, Deprecated, Use Identify struct
// Should the session request compressed websocket data. // Should the session request compressed websocket data.
Compress bool Compress bool
@ -911,6 +918,59 @@ type GatewayBotResponse struct {
Shards int `json:"shards"` Shards int `json:"shards"`
} }
// GatewayStatusUpdate is sent by the client to indicate a presence or status update
// https://discordapp.com/developers/docs/topics/gateway#update-status-gateway-status-update-structure
type GatewayStatusUpdate struct {
Since int `json:"since"`
Game Activity `json:"game"`
Status string `json:"status"`
AFK bool `json:"afk"`
}
// Activity defines the Activity sent with GatewayStatusUpdate
// https://discordapp.com/developers/docs/topics/gateway#activity-object
type Activity struct {
Name string
Type ActivityType
URL string
}
// ActivityType is the type of Activity (see ActivityType* consts) in the Activity struct
// https://discordapp.com/developers/docs/topics/gateway#activity-object-activity-types
type ActivityType int
// Valid ActivityType values
// https://discordapp.com/developers/docs/topics/gateway#activity-object-activity-types
const (
ActivityTypeGame GameType = iota
ActivityTypeStreaming
ActivityTypeListening
// ActivityTypeWatching // not valid in this use case?
ActivityTypeCustom = 4
)
// Identify is sent during initial handshake with the discord gateway.
// https://discordapp.com/developers/docs/topics/gateway#identify
type Identify struct {
Token string `json:"token"`
Properties IdentifyProperties `json:"properties"`
Compress bool `json:"compress"`
LargeThreshold int `json:"large_threshold"`
Shard *[2]int `json:"shard,omitempty"`
Presence GatewayStatusUpdate `json:"presence,omitempty"`
GuildSubscriptions bool `json:"guild_subscriptions"`
}
// IdentifyProperties contains the "properties" portion of an Identify packet
// https://discordapp.com/developers/docs/topics/gateway#identify-identify-connection-properties
type IdentifyProperties struct {
OS string `json:"$os"`
Browser string `json:"$browser"`
Device string `json:"$device"`
Referer string `json:"$referer"`
ReferringDomain string `json:"$referring_domain"`
}
// Constants for the different bit offsets of text channel permissions // Constants for the different bit offsets of text channel permissions
const ( const (
PermissionReadMessages = 1 << (iota + 10) PermissionReadMessages = 1 << (iota + 10)

View file

@ -18,7 +18,6 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"runtime"
"sync/atomic" "sync/atomic"
"time" "time"
@ -741,55 +740,42 @@ func (s *Session) onVoiceServerUpdate(st *VoiceServerUpdate) {
} }
} }
type identifyProperties struct {
OS string `json:"$os"`
Browser string `json:"$browser"`
Device string `json:"$device"`
Referer string `json:"$referer"`
ReferringDomain string `json:"$referring_domain"`
}
type identifyData struct {
Token string `json:"token"`
Properties identifyProperties `json:"properties"`
LargeThreshold int `json:"large_threshold"`
Compress bool `json:"compress"`
Shard *[2]int `json:"shard,omitempty"`
}
type identifyOp struct { type identifyOp struct {
Op int `json:"op"` Op int `json:"op"`
Data identifyData `json:"d"` Data Identify `json:"d"`
} }
// identify sends the identify packet to the gateway // identify sends the identify packet to the gateway
func (s *Session) identify() error { func (s *Session) identify() error {
s.log(LogDebug, "called")
properties := identifyProperties{runtime.GOOS, // TODO: This is a temporary block of code to help
"Discordgo v" + VERSION, // maintain backwards compatability
"", if s.Compress == false {
"", s.Identify.Compress = false
"",
} }
data := identifyData{s.Token, // TODO: This is a temporary block of code to help
properties, // maintain backwards compatability
250, if s.Token != "" && s.Identify.Token == "" {
s.Compress, s.Identify.Token = s.Token
nil,
} }
// TODO: Below block should be refactored so ShardID and ShardCount
// can be deprecated and their usage moved to the Session.Identify
// struct
if s.ShardCount > 1 { if s.ShardCount > 1 {
if s.ShardID >= s.ShardCount { if s.ShardID >= s.ShardCount {
return ErrWSShardBounds return ErrWSShardBounds
} }
data.Shard = &[2]int{s.ShardID, s.ShardCount} s.Identify.Shard = &[2]int{s.ShardID, s.ShardCount}
} }
op := identifyOp{2, data} // Send Identify packet to Discord
op := identifyOp{2, s.Identify}
s.log(LogDebug, "Identify Packet: \n%#v", op)
s.wsMutex.Lock() s.wsMutex.Lock()
err := s.wsConn.WriteJSON(op) err := s.wsConn.WriteJSON(op)
s.wsMutex.Unlock() s.wsMutex.Unlock()