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()