Merge pull request #866 from bwmarrin/v8
Switch library to API version v8
This commit is contained in:
commit
cbfa831b6c
14 changed files with 114 additions and 128 deletions
|
@ -22,7 +22,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
|
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
|
||||||
const VERSION = "0.22.0"
|
const VERSION = "0.23.0-v8alpha"
|
||||||
|
|
||||||
// ErrMFA will be risen by New when the user has 2FA.
|
// ErrMFA will be risen by New when the user has 2FA.
|
||||||
var ErrMFA = errors.New("account has 2FA enabled")
|
var ErrMFA = errors.New("account has 2FA enabled")
|
||||||
|
|
|
@ -125,7 +125,7 @@ func TestOpenClose(t *testing.T) {
|
||||||
// UpdateStatus - maybe we move this into wsapi_test.go but the websocket
|
// UpdateStatus - maybe we move this into wsapi_test.go but the websocket
|
||||||
// created here is needed. This helps tests that the websocket was setup
|
// created here is needed. This helps tests that the websocket was setup
|
||||||
// and it is working.
|
// and it is working.
|
||||||
if err = d.UpdateStatus(0, time.Now().String()); err != nil {
|
if err = d.UpdateGameStatus(0, time.Now().String()); err != nil {
|
||||||
t.Errorf("UpdateStatus error: %+v", err)
|
t.Errorf("UpdateStatus error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ package discordgo
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
// APIVersion is the Discord API version used for the REST and Websocket API.
|
// APIVersion is the Discord API version used for the REST and Websocket API.
|
||||||
var APIVersion = "6"
|
var APIVersion = "8"
|
||||||
|
|
||||||
// Known Discord API Endpoints.
|
// Known Discord API Endpoints.
|
||||||
var (
|
var (
|
||||||
|
@ -90,7 +90,8 @@ var (
|
||||||
EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" }
|
EndpointGuildRoles = func(gID string) string { return EndpointGuilds + gID + "/roles" }
|
||||||
EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID }
|
EndpointGuildRole = func(gID, rID string) string { return EndpointGuilds + gID + "/roles/" + rID }
|
||||||
EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" }
|
EndpointGuildInvites = func(gID string) string { return EndpointGuilds + gID + "/invites" }
|
||||||
EndpointGuildEmbed = func(gID string) string { return EndpointGuilds + gID + "/embed" }
|
EndpointGuildWidget = func(gID string) string { return EndpointGuilds + gID + "/widget" }
|
||||||
|
EndpointGuildEmbed = EndpointGuildWidget
|
||||||
EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" }
|
EndpointGuildPrune = func(gID string) string { return EndpointGuilds + gID + "/prune" }
|
||||||
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
|
EndpointGuildIcon = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".png" }
|
||||||
EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
|
EndpointGuildIconAnimated = func(gID, hash string) string { return EndpointCDNIcons + gID + "/" + hash + ".gif" }
|
||||||
|
|
|
@ -197,7 +197,6 @@ type PresencesReplace []*Presence
|
||||||
type PresenceUpdate struct {
|
type PresenceUpdate struct {
|
||||||
Presence
|
Presence
|
||||||
GuildID string `json:"guild_id"`
|
GuildID string `json:"guild_id"`
|
||||||
Roles []string `json:"roles"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resumed is the data for a Resumed event.
|
// Resumed is the data for a Resumed event.
|
||||||
|
|
|
@ -55,7 +55,7 @@ func main() {
|
||||||
|
|
||||||
// We need information about guilds (which includes their channels),
|
// We need information about guilds (which includes their channels),
|
||||||
// messages and voice states.
|
// messages and voice states.
|
||||||
dg.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuilds | discordgo.IntentsGuildMessages | discordgo.IntentsGuildVoiceStates)
|
dg.Identify.Intents = discordgo.IntentsGuilds | discordgo.IntentsGuildMessages | discordgo.IntentsGuildVoiceStates
|
||||||
|
|
||||||
// Open the websocket and begin listening.
|
// Open the websocket and begin listening.
|
||||||
err = dg.Open()
|
err = dg.Open()
|
||||||
|
@ -78,7 +78,7 @@ func main() {
|
||||||
func ready(s *discordgo.Session, event *discordgo.Ready) {
|
func ready(s *discordgo.Session, event *discordgo.Ready) {
|
||||||
|
|
||||||
// Set the playing status.
|
// Set the playing status.
|
||||||
s.UpdateStatus(0, "!airhorn")
|
s.UpdateGameStatus(0, "!airhorn")
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will be called (due to AddHandler above) every time a new
|
// This function will be called (due to AddHandler above) every time a new
|
||||||
|
|
|
@ -34,7 +34,7 @@ func main() {
|
||||||
dg.AddHandler(messageCreate)
|
dg.AddHandler(messageCreate)
|
||||||
|
|
||||||
// In this example, we only care about receiving message events.
|
// In this example, we only care about receiving message events.
|
||||||
dg.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuildMessages)
|
dg.Identify.Intents = discordgo.IntentsGuildMessages
|
||||||
|
|
||||||
// Open a websocket connection to Discord and begin listening.
|
// Open a websocket connection to Discord and begin listening.
|
||||||
err = dg.Open()
|
err = dg.Open()
|
||||||
|
|
|
@ -75,7 +75,7 @@ func main() {
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
// We only really care about receiving voice state updates.
|
// We only really care about receiving voice state updates.
|
||||||
s.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsGuildVoiceStates)
|
s.Identify.Intents = discordgo.IntentsGuildVoiceStates
|
||||||
|
|
||||||
err = s.Open()
|
err = s.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -34,8 +34,10 @@ const (
|
||||||
MessageTypeUserPremiumGuildSubscriptionTierTwo
|
MessageTypeUserPremiumGuildSubscriptionTierTwo
|
||||||
MessageTypeUserPremiumGuildSubscriptionTierThree
|
MessageTypeUserPremiumGuildSubscriptionTierThree
|
||||||
MessageTypeChannelFollowAdd
|
MessageTypeChannelFollowAdd
|
||||||
MessageTypeGuildDiscoveryDisqualified
|
MessageTypeGuildDiscoveryDisqualified = iota + 1
|
||||||
MessageTypeGuildDiscoveryRequalified
|
MessageTypeGuildDiscoveryRequalified
|
||||||
|
MessageTypeReply = iota + 4
|
||||||
|
MessageTypeApplicationCommand
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Message stores all data related to a specific Discord message.
|
// A Message stores all data related to a specific Discord message.
|
||||||
|
|
15
ratelimit.go
15
ratelimit.go
|
@ -1,6 +1,7 @@
|
||||||
package discordgo
|
package discordgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -140,20 +141,21 @@ func (b *Bucket) Release(headers http.Header) error {
|
||||||
remaining := headers.Get("X-RateLimit-Remaining")
|
remaining := headers.Get("X-RateLimit-Remaining")
|
||||||
reset := headers.Get("X-RateLimit-Reset")
|
reset := headers.Get("X-RateLimit-Reset")
|
||||||
global := headers.Get("X-RateLimit-Global")
|
global := headers.Get("X-RateLimit-Global")
|
||||||
retryAfter := headers.Get("Retry-After")
|
resetAfter := headers.Get("X-RateLimit-Reset-After")
|
||||||
|
|
||||||
// Update global and per bucket reset time if the proper headers are available
|
// Update global and per bucket reset time if the proper headers are available
|
||||||
// If global is set, then it will block all buckets until after Retry-After
|
// If global is set, then it will block all buckets until after Retry-After
|
||||||
// If Retry-After without global is provided it will use that for the new reset
|
// If Retry-After without global is provided it will use that for the new reset
|
||||||
// time since it's more accurate than X-RateLimit-Reset.
|
// time since it's more accurate than X-RateLimit-Reset.
|
||||||
// If Retry-After after is not proided, it will update the reset time from X-RateLimit-Reset
|
// If Retry-After after is not proided, it will update the reset time from X-RateLimit-Reset
|
||||||
if retryAfter != "" {
|
if resetAfter != "" {
|
||||||
parsedAfter, err := strconv.ParseInt(retryAfter, 10, 64)
|
parsedAfter, err := strconv.ParseFloat(resetAfter, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resetAt := time.Now().Add(time.Duration(parsedAfter) * time.Millisecond)
|
whole, frac := math.Modf(parsedAfter)
|
||||||
|
resetAt := time.Now().Add(time.Duration(whole) * time.Second).Add(time.Duration(frac*1000) * time.Millisecond)
|
||||||
|
|
||||||
// Lock either this single bucket or all buckets
|
// Lock either this single bucket or all buckets
|
||||||
if global != "" {
|
if global != "" {
|
||||||
|
@ -168,7 +170,7 @@ func (b *Bucket) Release(headers http.Header) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
unix, err := strconv.ParseInt(reset, 10, 64)
|
unix, err := strconv.ParseFloat(reset, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -177,7 +179,8 @@ func (b *Bucket) Release(headers http.Header) error {
|
||||||
// some extra time is added because without it i still encountered 429's.
|
// some extra time is added because without it i still encountered 429's.
|
||||||
// The added amount is the lowest amount that gave no 429's
|
// The added amount is the lowest amount that gave no 429's
|
||||||
// in 1k requests
|
// in 1k requests
|
||||||
delta := time.Unix(unix, 0).Sub(discordTime) + time.Millisecond*250
|
whole, frac := math.Modf(unix)
|
||||||
|
delta := time.Unix(int64(whole), 0).Add(time.Duration(frac*1000)*time.Millisecond).Sub(discordTime) + time.Millisecond*250
|
||||||
b.reset = time.Now().Add(delta)
|
b.reset = time.Now().Add(delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package discordgo
|
package discordgo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -18,7 +19,7 @@ func TestRatelimitReset(t *testing.T) {
|
||||||
|
|
||||||
headers.Set("X-RateLimit-Remaining", "0")
|
headers.Set("X-RateLimit-Remaining", "0")
|
||||||
// Reset for approx 2 seconds from now
|
// Reset for approx 2 seconds from now
|
||||||
headers.Set("X-RateLimit-Reset", strconv.FormatInt(time.Now().Add(time.Second*2).Unix(), 10))
|
headers.Set("X-RateLimit-Reset", fmt.Sprint(float64(time.Now().Add(time.Second*2).UnixNano())/1e9))
|
||||||
headers.Set("Date", time.Now().Format(time.RFC850))
|
headers.Set("Date", time.Now().Format(time.RFC850))
|
||||||
|
|
||||||
err := bucket.Release(headers)
|
err := bucket.Release(headers)
|
||||||
|
@ -56,7 +57,7 @@ func TestRatelimitGlobal(t *testing.T) {
|
||||||
|
|
||||||
headers.Set("X-RateLimit-Global", "1")
|
headers.Set("X-RateLimit-Global", "1")
|
||||||
// Reset for approx 1 seconds from now
|
// Reset for approx 1 seconds from now
|
||||||
headers.Set("Retry-After", "1000")
|
headers.Set("X-RateLimit-Reset-After", "1")
|
||||||
|
|
||||||
err := bucket.Release(headers)
|
err := bucket.Release(headers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -105,7 +106,7 @@ func sendBenchReq(endpoint string, rl *RateLimiter) {
|
||||||
headers := http.Header(make(map[string][]string))
|
headers := http.Header(make(map[string][]string))
|
||||||
|
|
||||||
headers.Set("X-RateLimit-Remaining", "10")
|
headers.Set("X-RateLimit-Remaining", "10")
|
||||||
headers.Set("X-RateLimit-Reset", strconv.FormatInt(time.Now().Unix(), 10))
|
headers.Set("X-RateLimit-Reset", fmt.Sprint(float64(time.Now().UnixNano())/1e9))
|
||||||
headers.Set("Date", time.Now().Format(time.RFC850))
|
headers.Set("Date", time.Now().Format(time.RFC850))
|
||||||
|
|
||||||
bucket.Release(headers)
|
bucket.Release(headers)
|
||||||
|
|
18
restapi.go
18
restapi.go
|
@ -465,7 +465,7 @@ func (s *Session) UserGuildSettingsEdit(guildID string, settings *UserGuildSetti
|
||||||
//
|
//
|
||||||
// NOTE: This function is now deprecated and will be removed in the future.
|
// NOTE: This function is now deprecated and will be removed in the future.
|
||||||
// Please see the same function inside state.go
|
// Please see the same function inside state.go
|
||||||
func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions int, err error) {
|
func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions int64, err error) {
|
||||||
// Try to just get permissions from state.
|
// Try to just get permissions from state.
|
||||||
apermissions, err = s.State.UserChannelPermissions(userID, channelID)
|
apermissions, err = s.State.UserChannelPermissions(userID, channelID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -507,7 +507,7 @@ func (s *Session) UserChannelPermissions(userID, channelID string) (apermissions
|
||||||
|
|
||||||
// Calculates the permissions for a member.
|
// Calculates the permissions for a member.
|
||||||
// https://support.discord.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured-
|
// https://support.discord.com/hc/en-us/articles/206141927-How-is-the-permission-hierarchy-structured-
|
||||||
func memberPermissions(guild *Guild, channel *Channel, userID string, roles []string) (apermissions int) {
|
func memberPermissions(guild *Guild, channel *Channel, userID string, roles []string) (apermissions int64) {
|
||||||
if userID == guild.OwnerID {
|
if userID == guild.OwnerID {
|
||||||
apermissions = PermissionAll
|
apermissions = PermissionAll
|
||||||
return
|
return
|
||||||
|
@ -542,13 +542,11 @@ func memberPermissions(guild *Guild, channel *Channel, userID string, roles []st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
denies := 0
|
var denies, allows int64
|
||||||
allows := 0
|
|
||||||
|
|
||||||
// Member overwrites can override role overrides, so do two passes
|
// Member overwrites can override role overrides, so do two passes
|
||||||
for _, overwrite := range channel.PermissionOverwrites {
|
for _, overwrite := range channel.PermissionOverwrites {
|
||||||
for _, roleID := range roles {
|
for _, roleID := range roles {
|
||||||
if overwrite.Type == "role" && roleID == overwrite.ID {
|
if overwrite.Type == PermissionOverwriteTypeRole && roleID == overwrite.ID {
|
||||||
denies |= overwrite.Deny
|
denies |= overwrite.Deny
|
||||||
allows |= overwrite.Allow
|
allows |= overwrite.Allow
|
||||||
break
|
break
|
||||||
|
@ -560,7 +558,7 @@ func memberPermissions(guild *Guild, channel *Channel, userID string, roles []st
|
||||||
apermissions |= allows
|
apermissions |= allows
|
||||||
|
|
||||||
for _, overwrite := range channel.PermissionOverwrites {
|
for _, overwrite := range channel.PermissionOverwrites {
|
||||||
if overwrite.Type == "member" && overwrite.ID == userID {
|
if overwrite.Type == PermissionOverwriteTypeMember && overwrite.ID == userID {
|
||||||
apermissions &= ^overwrite.Deny
|
apermissions &= ^overwrite.Deny
|
||||||
apermissions |= overwrite.Allow
|
apermissions |= overwrite.Allow
|
||||||
break
|
break
|
||||||
|
@ -717,7 +715,7 @@ func (s *Session) GuildBanCreateWithReason(guildID, userID, reason string, days
|
||||||
|
|
||||||
queryParams := url.Values{}
|
queryParams := url.Values{}
|
||||||
if days > 0 {
|
if days > 0 {
|
||||||
queryParams.Set("delete-message-days", strconv.Itoa(days))
|
queryParams.Set("delete_message_days", strconv.Itoa(days))
|
||||||
}
|
}
|
||||||
if reason != "" {
|
if reason != "" {
|
||||||
queryParams.Set("reason", reason)
|
queryParams.Set("reason", reason)
|
||||||
|
@ -1809,11 +1807,11 @@ func (s *Session) ChannelInviteCreate(channelID string, i Invite) (st *Invite, e
|
||||||
// ChannelPermissionSet creates a Permission Override for the given channel.
|
// ChannelPermissionSet creates a Permission Override for the given channel.
|
||||||
// NOTE: This func name may changed. Using Set instead of Create because
|
// NOTE: This func name may changed. Using Set instead of Create because
|
||||||
// you can both create a new override or update an override with this function.
|
// you can both create a new override or update an override with this function.
|
||||||
func (s *Session) ChannelPermissionSet(channelID, targetID, targetType string, allow, deny int) (err error) {
|
func (s *Session) ChannelPermissionSet(channelID, targetID string, targetType PermissionOverwriteType, allow, deny int) (err error) {
|
||||||
|
|
||||||
data := struct {
|
data := struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Type string `json:"type"`
|
Type PermissionOverwriteType `json:"type"`
|
||||||
Allow int `json:"allow"`
|
Allow int `json:"allow"`
|
||||||
Deny int `json:"deny"`
|
Deny int `json:"deny"`
|
||||||
}{targetID, targetType, allow, deny}
|
}{targetID, targetType, allow, deny}
|
||||||
|
|
22
state.go
22
state.go
|
@ -200,14 +200,10 @@ func (s *State) PresenceAdd(guildID string, presence *Presence) error {
|
||||||
//guild.Presences[i] = presence
|
//guild.Presences[i] = presence
|
||||||
|
|
||||||
//Update status
|
//Update status
|
||||||
guild.Presences[i].Game = presence.Game
|
guild.Presences[i].Activities = presence.Activities
|
||||||
guild.Presences[i].Roles = presence.Roles
|
|
||||||
if presence.Status != "" {
|
if presence.Status != "" {
|
||||||
guild.Presences[i].Status = presence.Status
|
guild.Presences[i].Status = presence.Status
|
||||||
}
|
}
|
||||||
if presence.Nick != "" {
|
|
||||||
guild.Presences[i].Nick = presence.Nick
|
|
||||||
}
|
|
||||||
|
|
||||||
//Update the optionally sent user information
|
//Update the optionally sent user information
|
||||||
//ID Is a mandatory field so you should not need to check if it is empty
|
//ID Is a mandatory field so you should not need to check if it is empty
|
||||||
|
@ -966,24 +962,12 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
|
||||||
// Member not found; this is a user coming online
|
// Member not found; this is a user coming online
|
||||||
m = &Member{
|
m = &Member{
|
||||||
GuildID: t.GuildID,
|
GuildID: t.GuildID,
|
||||||
Nick: t.Nick,
|
|
||||||
User: t.User,
|
User: t.User,
|
||||||
Roles: t.Roles,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if t.Nick != "" {
|
|
||||||
m.Nick = t.Nick
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.User.Username != "" {
|
if t.User.Username != "" {
|
||||||
m.User.Username = t.User.Username
|
m.User.Username = t.User.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
// PresenceUpdates always contain a list of roles, so there's no need to check for an empty list here
|
|
||||||
m.Roles = t.Roles
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.MemberAdd(m)
|
err = s.MemberAdd(m)
|
||||||
|
@ -997,7 +981,7 @@ func (s *State) OnInterface(se *Session, i interface{}) (err error) {
|
||||||
// UserChannelPermissions returns the permission of a user in a channel.
|
// UserChannelPermissions returns the permission of a user in a channel.
|
||||||
// userID : The ID of the user to calculate permissions for.
|
// userID : The ID of the user to calculate permissions for.
|
||||||
// channelID : The ID of the channel to calculate permission for.
|
// channelID : The ID of the channel to calculate permission for.
|
||||||
func (s *State) UserChannelPermissions(userID, channelID string) (apermissions int, err error) {
|
func (s *State) UserChannelPermissions(userID, channelID string) (apermissions int64, err error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return 0, ErrNilState
|
return 0, ErrNilState
|
||||||
}
|
}
|
||||||
|
@ -1022,7 +1006,7 @@ func (s *State) UserChannelPermissions(userID, channelID string) (apermissions i
|
||||||
|
|
||||||
// MessagePermissions returns the permissions of the author of the message
|
// MessagePermissions returns the permissions of the author of the message
|
||||||
// in the channel in which it was sent.
|
// in the channel in which it was sent.
|
||||||
func (s *State) MessagePermissions(message *Message) (apermissions int, err error) {
|
func (s *State) MessagePermissions(message *Message) (apermissions int64, err error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return 0, ErrNilState
|
return 0, ErrNilState
|
||||||
}
|
}
|
||||||
|
|
92
structs.go
92
structs.go
|
@ -14,6 +14,7 @@ package discordgo
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -322,12 +323,22 @@ type ChannelFollow struct {
|
||||||
WebhookID string `json:"webhook_id"`
|
WebhookID string `json:"webhook_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PermissionOverwriteType represents the type of resource on which
|
||||||
|
// a permission overwrite acts.
|
||||||
|
type PermissionOverwriteType int
|
||||||
|
|
||||||
|
// The possible permission overwrite types.
|
||||||
|
const (
|
||||||
|
PermissionOverwriteTypeRole PermissionOverwriteType = iota
|
||||||
|
PermissionOverwriteTypeMember
|
||||||
|
)
|
||||||
|
|
||||||
// A PermissionOverwrite holds permission overwrite data for a Channel
|
// A PermissionOverwrite holds permission overwrite data for a Channel
|
||||||
type PermissionOverwrite struct {
|
type PermissionOverwrite struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Type string `json:"type"`
|
Type PermissionOverwriteType `json:"type"`
|
||||||
Deny int `json:"deny"`
|
Deny int64 `json:"deny,string"`
|
||||||
Allow int `json:"allow"`
|
Allow int64 `json:"allow,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emoji struct holds data related to Emoji's
|
// Emoji struct holds data related to Emoji's
|
||||||
|
@ -427,9 +438,6 @@ type Guild struct {
|
||||||
// The ID of the AFK voice channel.
|
// The ID of the AFK voice channel.
|
||||||
AfkChannelID string `json:"afk_channel_id"`
|
AfkChannelID string `json:"afk_channel_id"`
|
||||||
|
|
||||||
// The ID of the embed channel ID, used for embed widgets.
|
|
||||||
EmbedChannelID string `json:"embed_channel_id"`
|
|
||||||
|
|
||||||
// The user ID of the owner of the guild.
|
// The user ID of the owner of the guild.
|
||||||
OwnerID string `json:"owner_id"`
|
OwnerID string `json:"owner_id"`
|
||||||
|
|
||||||
|
@ -458,9 +466,6 @@ type Guild struct {
|
||||||
// The verification level required for the guild.
|
// The verification level required for the guild.
|
||||||
VerificationLevel VerificationLevel `json:"verification_level"`
|
VerificationLevel VerificationLevel `json:"verification_level"`
|
||||||
|
|
||||||
// Whether the guild has embedding enabled.
|
|
||||||
EmbedEnabled bool `json:"embed_enabled"`
|
|
||||||
|
|
||||||
// Whether the guild is considered large. This is
|
// Whether the guild is considered large. This is
|
||||||
// determined by a member threshold in the identify packet,
|
// determined by a member threshold in the identify packet,
|
||||||
// and is currently hard-coded at 250 members in the library.
|
// and is currently hard-coded at 250 members in the library.
|
||||||
|
@ -564,7 +569,7 @@ type Guild struct {
|
||||||
ApproximatePresenceCount int `json:"approximate_presence_count"`
|
ApproximatePresenceCount int `json:"approximate_presence_count"`
|
||||||
|
|
||||||
// Permissions of our user
|
// Permissions of our user
|
||||||
Permissions int `json:"permissions"`
|
Permissions int64 `json:"permissions,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessageNotifications is the notification level for a guild
|
// MessageNotifications is the notification level for a guild
|
||||||
|
@ -606,7 +611,7 @@ type UserGuild struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Icon string `json:"icon"`
|
Icon string `json:"icon"`
|
||||||
Owner bool `json:"owner"`
|
Owner bool `json:"owner"`
|
||||||
Permissions int `json:"permissions"`
|
Permissions int64 `json:"permissions,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// A GuildParams stores all the data needed to update discord guild settings
|
// A GuildParams stores all the data needed to update discord guild settings
|
||||||
|
@ -650,7 +655,7 @@ type Role struct {
|
||||||
// The permissions of the role on the guild (doesn't include channel overrides).
|
// The permissions of the role on the guild (doesn't include channel overrides).
|
||||||
// This is a combination of bit masks; the presence of a certain permission can
|
// This is a combination of bit masks; the presence of a certain permission can
|
||||||
// be checked by performing a bitwise AND between this int and the permission.
|
// be checked by performing a bitwise AND between this int and the permission.
|
||||||
Permissions int `json:"permissions"`
|
Permissions int64 `json:"permissions,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mention returns a string which mentions the role
|
// Mention returns a string which mentions the role
|
||||||
|
@ -690,39 +695,10 @@ type VoiceState struct {
|
||||||
type Presence struct {
|
type Presence struct {
|
||||||
User *User `json:"user"`
|
User *User `json:"user"`
|
||||||
Status Status `json:"status"`
|
Status Status `json:"status"`
|
||||||
Game *Game `json:"game"`
|
Activities []*Activity `json:"activities"`
|
||||||
Activities []*Game `json:"activities"`
|
|
||||||
Nick string `json:"nick"`
|
|
||||||
Roles []string `json:"roles"`
|
|
||||||
Since *int `json:"since"`
|
Since *int `json:"since"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GameType is the type of "game" (see GameType* consts) in the Game struct
|
|
||||||
type GameType int
|
|
||||||
|
|
||||||
// Valid GameType values
|
|
||||||
const (
|
|
||||||
GameTypeGame GameType = iota
|
|
||||||
GameTypeStreaming
|
|
||||||
GameTypeListening
|
|
||||||
GameTypeWatching
|
|
||||||
GameTypeCustom
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Game struct holds the name of the "playing .." game for a user
|
|
||||||
type Game struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Type GameType `json:"type"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Details string `json:"details,omitempty"`
|
|
||||||
State string `json:"state,omitempty"`
|
|
||||||
TimeStamps TimeStamps `json:"timestamps,omitempty"`
|
|
||||||
Assets Assets `json:"assets,omitempty"`
|
|
||||||
ApplicationID string `json:"application_id,omitempty"`
|
|
||||||
Instance int8 `json:"instance,omitempty"`
|
|
||||||
// TODO: Party and Secrets (unknown structure)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A TimeStamps struct contains start and end times used in the rich presence "playing .." Game
|
// A TimeStamps struct contains start and end times used in the rich presence "playing .." Game
|
||||||
type TimeStamps struct {
|
type TimeStamps struct {
|
||||||
EndTimestamp int64 `json:"end,omitempty"`
|
EndTimestamp int64 `json:"end,omitempty"`
|
||||||
|
@ -841,6 +817,26 @@ type TooManyRequests struct {
|
||||||
RetryAfter time.Duration `json:"retry_after"`
|
RetryAfter time.Duration `json:"retry_after"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON helps support translation of a milliseconds-based float
|
||||||
|
// into a time.Duration on TooManyRequests.
|
||||||
|
func (t *TooManyRequests) UnmarshalJSON(b []byte) error {
|
||||||
|
u := struct {
|
||||||
|
Bucket string `json:"bucket"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
RetryAfter float64 `json:"retry_after"`
|
||||||
|
}{}
|
||||||
|
err := json.Unmarshal(b, &u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Bucket = u.Bucket
|
||||||
|
t.Message = u.Message
|
||||||
|
whole, frac := math.Modf(u.RetryAfter)
|
||||||
|
t.RetryAfter = time.Duration(whole)*time.Second + time.Duration(frac*1000)*time.Millisecond
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// A ReadState stores data on the read state of channels.
|
// A ReadState stores data on the read state of channels.
|
||||||
type ReadState struct {
|
type ReadState struct {
|
||||||
MentionCount int `json:"mention_count"`
|
MentionCount int `json:"mention_count"`
|
||||||
|
@ -1131,7 +1127,7 @@ type ActivityType int
|
||||||
|
|
||||||
// Valid ActivityType values
|
// Valid ActivityType values
|
||||||
const (
|
const (
|
||||||
ActivityTypeGame GameType = iota
|
ActivityTypeGame ActivityType = iota
|
||||||
ActivityTypeStreaming
|
ActivityTypeStreaming
|
||||||
ActivityTypeListening
|
ActivityTypeListening
|
||||||
// ActivityTypeWatching // not valid in this use case?
|
// ActivityTypeWatching // not valid in this use case?
|
||||||
|
@ -1148,7 +1144,7 @@ type Identify struct {
|
||||||
Shard *[2]int `json:"shard,omitempty"`
|
Shard *[2]int `json:"shard,omitempty"`
|
||||||
Presence GatewayStatusUpdate `json:"presence,omitempty"`
|
Presence GatewayStatusUpdate `json:"presence,omitempty"`
|
||||||
GuildSubscriptions bool `json:"guild_subscriptions"`
|
GuildSubscriptions bool `json:"guild_subscriptions"`
|
||||||
Intents *Intent `json:"intents,omitempty"`
|
Intents Intent `json:"intents"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IdentifyProperties contains the "properties" portion of an Identify packet
|
// IdentifyProperties contains the "properties" portion of an Identify packet
|
||||||
|
@ -1335,7 +1331,9 @@ const (
|
||||||
IntentsNone Intent = 0
|
IntentsNone Intent = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeIntent helps convert a gateway intent value for use in the Identify structure.
|
// MakeIntent used to help convert a gateway intent value for use in the Identify structure;
|
||||||
func MakeIntent(intents Intent) *Intent {
|
// this was useful to help support the use of a pointer type when intents were optional.
|
||||||
return &intents
|
// This is now a no-op, and is not necessary to use.
|
||||||
|
func MakeIntent(intents Intent) Intent {
|
||||||
|
return intents
|
||||||
}
|
}
|
||||||
|
|
44
wsapi.go
44
wsapi.go
|
@ -323,7 +323,7 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}
|
||||||
// UpdateStatusData ia provided to UpdateStatusComplex()
|
// UpdateStatusData ia provided to UpdateStatusComplex()
|
||||||
type UpdateStatusData struct {
|
type UpdateStatusData struct {
|
||||||
IdleSince *int `json:"since"`
|
IdleSince *int `json:"since"`
|
||||||
Game *Game `json:"game"`
|
Activities []*Activity `json:"activities"`
|
||||||
AFK bool `json:"afk"`
|
AFK bool `json:"afk"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ type updateStatusOp struct {
|
||||||
Data UpdateStatusData `json:"d"`
|
Data UpdateStatusData `json:"d"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUpdateStatusData(idle int, gameType GameType, game, url string) *UpdateStatusData {
|
func newUpdateStatusData(idle int, activityType ActivityType, name, url string) *UpdateStatusData {
|
||||||
usd := &UpdateStatusData{
|
usd := &UpdateStatusData{
|
||||||
Status: "online",
|
Status: "online",
|
||||||
}
|
}
|
||||||
|
@ -342,43 +342,43 @@ func newUpdateStatusData(idle int, gameType GameType, game, url string) *UpdateS
|
||||||
usd.IdleSince = &idle
|
usd.IdleSince = &idle
|
||||||
}
|
}
|
||||||
|
|
||||||
if game != "" {
|
if name != "" {
|
||||||
usd.Game = &Game{
|
usd.Activities = []*Activity{{
|
||||||
Name: game,
|
Name: name,
|
||||||
Type: gameType,
|
Type: activityType,
|
||||||
URL: url,
|
URL: url,
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
return usd
|
return usd
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatus is used to update the user's status.
|
// UpdateGameStatus is used to update the user's status.
|
||||||
// If idle>0 then set status to idle.
|
// If idle>0 then set status to idle.
|
||||||
// If game!="" then set game.
|
// If name!="" then set game.
|
||||||
// if otherwise, set status to active, and no game.
|
// if otherwise, set status to active, and no activity.
|
||||||
func (s *Session) UpdateStatus(idle int, game string) (err error) {
|
func (s *Session) UpdateGameStatus(idle int, name string) (err error) {
|
||||||
return s.UpdateStatusComplex(*newUpdateStatusData(idle, GameTypeGame, game, ""))
|
return s.UpdateStatusComplex(*newUpdateStatusData(idle, ActivityTypeGame, name, ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStreamingStatus is used to update the user's streaming status.
|
// UpdateStreamingStatus is used to update the user's streaming status.
|
||||||
// If idle>0 then set status to idle.
|
// If idle>0 then set status to idle.
|
||||||
// If game!="" then set game.
|
// If name!="" then set game.
|
||||||
// If game!="" and url!="" then set the status type to streaming with the URL set.
|
// If name!="" and url!="" then set the status type to streaming with the URL set.
|
||||||
// if otherwise, set status to active, and no game.
|
// if otherwise, set status to active, and no game.
|
||||||
func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err error) {
|
func (s *Session) UpdateStreamingStatus(idle int, name string, url string) (err error) {
|
||||||
gameType := GameTypeGame
|
gameType := ActivityTypeGame
|
||||||
if url != "" {
|
if url != "" {
|
||||||
gameType = GameTypeStreaming
|
gameType = ActivityTypeStreaming
|
||||||
}
|
}
|
||||||
return s.UpdateStatusComplex(*newUpdateStatusData(idle, gameType, game, url))
|
return s.UpdateStatusComplex(*newUpdateStatusData(idle, gameType, name, url))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateListeningStatus is used to set the user to "Listening to..."
|
// UpdateListeningStatus is used to set the user to "Listening to..."
|
||||||
// If game!="" then set to what user is listening to
|
// If name!="" then set to what user is listening to
|
||||||
// Else, set user to active and no game.
|
// Else, set user to active and no activity.
|
||||||
func (s *Session) UpdateListeningStatus(game string) (err error) {
|
func (s *Session) UpdateListeningStatus(name string) (err error) {
|
||||||
return s.UpdateStatusComplex(*newUpdateStatusData(0, GameTypeListening, game, ""))
|
return s.UpdateStatusComplex(*newUpdateStatusData(0, ActivityTypeListening, name, ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateStatusComplex allows for sending the raw status update data untouched by discordgo.
|
// UpdateStatusComplex allows for sending the raw status update data untouched by discordgo.
|
||||||
|
|
Loading…
Reference in a new issue