From 973580a2baa483e0e4613c1b1afd32d474687f7a Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Mon, 20 Jan 2020 12:01:58 -0600 Subject: [PATCH 1/5] Initial commit of ExposeIdentify feature --- discord.go | 24 +++++++++++++++++------- structs.go | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ wsapi.go | 50 ++++++++++++++++++-------------------------------- 3 files changed, 88 insertions(+), 39 deletions(-) diff --git a/discord.go b/discord.go index 755b087..e0f6f63 100644 --- a/discord.go +++ b/discord.go @@ -17,6 +17,7 @@ import ( "errors" "fmt" "net/http" + "runtime" "time" ) @@ -63,6 +64,14 @@ func New(args ...interface{}) (s *Session, err error) { 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 args == nil { return @@ -94,7 +103,8 @@ func New(args ...interface{}) (s *Session, err error) { // If third string exists, it must be an auth token. 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: @@ -107,7 +117,8 @@ func New(args ...interface{}) (s *Session, err error) { } else if pass == "" { pass = v } else if s.Token == "" { - s.Token = v + s.Identify.Token = v + s.Token = v // TODO: Remove, Deprecated - Kept for backwards compatibility. } else { err = fmt.Errorf("too many string parameters provided") 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 // invalid. if pass == "" { - s.Token = auth + s.Identify.Token = auth + s.Token = auth // TODO: Remove, Deprecated - Kept for backwards compatibility. } else { 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 { err = ErrMFA } 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 } diff --git a/structs.go b/structs.go index 19bb5be..c509f3a 100644 --- a/structs.go +++ b/structs.go @@ -39,6 +39,11 @@ type Session struct { // Should the session reconnect the websocket on errors. 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 IDENTITY struct // Should the session request compressed websocket data. Compress bool @@ -909,6 +914,54 @@ type GatewayBotResponse struct { Shards int `json:"shards"` } +// Gateway Status Update 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"` +} + +type Activity struct { + Name string + Type ActivityType + URL string +} + +// GameType is the type of "game" (see GameType* consts) in the Game struct +// https://discordapp.com/developers/docs/topics/gateway#activity-object-activity-types +type ActivityType int + +// Valid GameType values +const ( + ActivityTypeGame GameType = iota + ActivityTypeStreaming + ActivityTypeListening + // ActivityTypeWatching // not valid in the use? + 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"` +} + +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 const ( PermissionReadMessages = 1 << (iota + 10) diff --git a/wsapi.go b/wsapi.go index c1fb91a..770c5df 100644 --- a/wsapi.go +++ b/wsapi.go @@ -18,7 +18,6 @@ import ( "fmt" "io" "net/http" - "runtime" "sync/atomic" "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 { - Op int `json:"op"` - Data identifyData `json:"d"` + Op int `json:"op"` + Data Identify `json:"d"` } // identify sends the identify packet to the gateway func (s *Session) identify() error { + s.log(LogDebug, "called") - properties := identifyProperties{runtime.GOOS, - "Discordgo v" + VERSION, - "", - "", - "", + // TODO: This is a temporary block of code to help + // maintain backwards compatability + if s.Compress == false { + s.Identify.Compress = false } - data := identifyData{s.Token, - properties, - 250, - s.Compress, - nil, + // TODO: This is a temporary block of code to help + // maintain backwards compatability + if s.Token != "" && s.Identify.Token == "" { + s.Identify.Token = s.Token } + // 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.ShardID >= s.ShardCount { 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() err := s.wsConn.WriteJSON(op) s.wsMutex.Unlock() From ee9178e2372894da113ae0bcaa9051cfa7b0faf2 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Mon, 20 Jan 2020 12:06:54 -0600 Subject: [PATCH 2/5] Fix wording --- structs.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/structs.go b/structs.go index c509f3a..f9b7f1f 100644 --- a/structs.go +++ b/structs.go @@ -29,8 +29,10 @@ type Session struct { // General configurable settings. // Authentication token for this session + // TODO: Remove Below, Deprecated, Use Identify struct Token string - MFA bool + + MFA bool // Debug for printing JSON request/responses Debug bool // Deprecated, will be removed. @@ -43,7 +45,7 @@ type Session struct { // https://discordapp.com/developers/docs/topics/gateway#identify Identify Identify - // TODO: REMOVE Below, DEPRECATED, Use IDENTITY struct + // TODO: Remove Below, Deprecated, Use Identify struct // Should the session request compressed websocket data. Compress bool From eff98faf41318a674260221bd3b82107618c7e8d Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Mon, 20 Jan 2020 12:10:20 -0600 Subject: [PATCH 3/5] Fix wording --- structs.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/structs.go b/structs.go index f9b7f1f..4e09194 100644 --- a/structs.go +++ b/structs.go @@ -925,22 +925,25 @@ type GatewayStatusUpdate struct { AFK bool `json:"afk"` } +// https://discordapp.com/developers/docs/topics/gateway#activity-object +// Activity defines the Activity sent with GatewayStatusUpdate type Activity struct { Name string Type ActivityType URL string } -// GameType is the type of "game" (see GameType* consts) in the Game struct +// 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 GameType values +// Valid ActivityType values +//https://discordapp.com/developers/docs/topics/gateway#activity-object-activity-types const ( ActivityTypeGame GameType = iota ActivityTypeStreaming ActivityTypeListening - // ActivityTypeWatching // not valid in the use? + // ActivityTypeWatching // not valid in this use case? ActivityTypeCustom = 4 ) From 69f369a9f41321d082db72ff9bf16c6714f5f8cd Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Mon, 20 Jan 2020 12:20:30 -0600 Subject: [PATCH 4/5] Linting. --- structs.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/structs.go b/structs.go index 4e09194..8abc1c6 100644 --- a/structs.go +++ b/structs.go @@ -916,7 +916,7 @@ type GatewayBotResponse struct { Shards int `json:"shards"` } -// Gateway Status Update is sent by the client to indicate a presence or status update +// 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"` @@ -925,8 +925,8 @@ type GatewayStatusUpdate struct { AFK bool `json:"afk"` } -// https://discordapp.com/developers/docs/topics/gateway#activity-object // Activity defines the Activity sent with GatewayStatusUpdate +// https://discordapp.com/developers/docs/topics/gateway#activity-object type Activity struct { Name string Type ActivityType @@ -959,6 +959,8 @@ type Identify struct { 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"` From 19c4a067d05b5835d314a8b4e651811c6c9bbf61 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Thu, 23 Jan 2020 09:33:36 -0600 Subject: [PATCH 5/5] Fixing Nits --- structs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/structs.go b/structs.go index 8abc1c6..f8f6707 100644 --- a/structs.go +++ b/structs.go @@ -938,7 +938,7 @@ type Activity struct { type ActivityType int // Valid ActivityType values -//https://discordapp.com/developers/docs/topics/gateway#activity-object-activity-types +// https://discordapp.com/developers/docs/topics/gateway#activity-object-activity-types const ( ActivityTypeGame GameType = iota ActivityTypeStreaming