|
@@ -18,7 +18,6 @@ import (
|
|
|
"fmt"
|
|
|
"io"
|
|
|
"net/http"
|
|
|
- "runtime"
|
|
|
"sync/atomic"
|
|
|
"time"
|
|
|
|
|
@@ -47,7 +46,7 @@ type resumePacket struct {
|
|
|
}
|
|
|
|
|
|
// Open creates a websocket connection to Discord.
|
|
|
-// See: https://discordapp.com/developers/docs/topics/gateway#connecting
|
|
|
+// See: https://discord.com/developers/docs/topics/gateway#connecting
|
|
|
func (s *Session) Open() error {
|
|
|
s.log(LogInformational, "called")
|
|
|
|
|
@@ -80,7 +79,7 @@ func (s *Session) Open() error {
|
|
|
header.Add("accept-encoding", "zlib")
|
|
|
s.wsConn, _, err = websocket.DefaultDialer.Dial(s.gateway, header)
|
|
|
if err != nil {
|
|
|
- s.log(LogWarning, "error connecting to gateway %s, %s", s.gateway, err)
|
|
|
+ s.log(LogError, "error connecting to gateway %s, %s", s.gateway, err)
|
|
|
s.gateway = "" // clear cached gateway
|
|
|
s.wsConn = nil // Just to be safe.
|
|
|
return err
|
|
@@ -399,9 +398,10 @@ func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
|
|
|
}
|
|
|
|
|
|
type requestGuildMembersData struct {
|
|
|
- GuildID string `json:"guild_id"`
|
|
|
- Query string `json:"query"`
|
|
|
- Limit int `json:"limit"`
|
|
|
+ GuildIDs []string `json:"guild_id"`
|
|
|
+ Query string `json:"query"`
|
|
|
+ Limit int `json:"limit"`
|
|
|
+ Presences bool `json:"presences"`
|
|
|
}
|
|
|
|
|
|
type requestGuildMembersOp struct {
|
|
@@ -411,10 +411,39 @@ type requestGuildMembersOp struct {
|
|
|
|
|
|
// RequestGuildMembers requests guild members from the gateway
|
|
|
// The gateway responds with GuildMembersChunk events
|
|
|
-// guildID : The ID of the guild to request members of
|
|
|
-// query : String that username starts with, leave empty to return all members
|
|
|
-// limit : Max number of items to return, or 0 to request all members matched
|
|
|
-func (s *Session) RequestGuildMembers(guildID, query string, limit int) (err error) {
|
|
|
+// guildID : Single Guild ID to request members of
|
|
|
+// query : String that username starts with, leave empty to return all members
|
|
|
+// limit : Max number of items to return, or 0 to request all members matched
|
|
|
+// presences : Whether to request presences of guild members
|
|
|
+func (s *Session) RequestGuildMembers(guildID string, query string, limit int, presences bool) (err error) {
|
|
|
+ data := requestGuildMembersData{
|
|
|
+ GuildIDs: []string{guildID},
|
|
|
+ Query: query,
|
|
|
+ Limit: limit,
|
|
|
+ Presences: presences,
|
|
|
+ }
|
|
|
+ err = s.requestGuildMembers(data)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// RequestGuildMembersBatch requests guild members from the gateway
|
|
|
+// The gateway responds with GuildMembersChunk events
|
|
|
+// guildID : Slice of guild IDs to request members of
|
|
|
+// query : String that username starts with, leave empty to return all members
|
|
|
+// limit : Max number of items to return, or 0 to request all members matched
|
|
|
+// presences : Whether to request presences of guild members
|
|
|
+func (s *Session) RequestGuildMembersBatch(guildIDs []string, query string, limit int, presences bool) (err error) {
|
|
|
+ data := requestGuildMembersData{
|
|
|
+ GuildIDs: guildIDs,
|
|
|
+ Query: query,
|
|
|
+ Limit: limit,
|
|
|
+ Presences: presences,
|
|
|
+ }
|
|
|
+ err = s.requestGuildMembers(data)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func (s *Session) requestGuildMembers(data requestGuildMembersData) (err error) {
|
|
|
s.log(LogInformational, "called")
|
|
|
|
|
|
s.RLock()
|
|
@@ -423,12 +452,6 @@ func (s *Session) RequestGuildMembers(guildID, query string, limit int) (err err
|
|
|
return ErrWSNotFound
|
|
|
}
|
|
|
|
|
|
- data := requestGuildMembersData{
|
|
|
- GuildID: guildID,
|
|
|
- Query: query,
|
|
|
- Limit: limit,
|
|
|
- }
|
|
|
-
|
|
|
s.wsMutex.Lock()
|
|
|
err = s.wsConn.WriteJSON(requestGuildMembersOp{8, data})
|
|
|
s.wsMutex.Unlock()
|
|
@@ -722,55 +745,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()
|
|
@@ -838,6 +848,13 @@ func (s *Session) Close() error {
|
|
|
}
|
|
|
|
|
|
// Close closes a websocket and stops all listening/heartbeat goroutines.
|
|
|
+// TODO: Add support for Voice WS/UDP
|
|
|
+func (s *Session) Close() error {
|
|
|
+ return s.CloseWithCode(websocket.CloseNormalClosure)
|
|
|
+}
|
|
|
+
|
|
|
+// CloseWithCode closes a websocket using the provided closeCode and stops all
|
|
|
+// listening/heartbeat goroutines.
|
|
|
// TODO: Add support for Voice WS/UDP connections
|
|
|
func (s *Session) CloseWithCode(closeCode int) (err error) {
|
|
|
|