discord: Refactor interaction commands and components
This commit is an amalgamation of the following local commits: - Fix UnknownCommandOption unmarshaling - Add missing ButtonComponent.UnmarshalJSON - Fix ButtonComponents Style unmarshaling - Remove debug logging - SelectComponent.ComponentEmoji - Fix incorrect CommandOption interface - Switch to pointer types for interfaces - Remove CommandOptionMeta - Less verbose CommandOption type names - Fix unused CommandInteractionOption - Remove ComponentInteractionData
This commit is contained in:
parent
123f8bc41f
commit
80b1dc3831
|
@ -19,82 +19,85 @@ func main() {
|
||||||
|
|
||||||
token := os.Getenv("BOT_TOKEN")
|
token := os.Getenv("BOT_TOKEN")
|
||||||
if token == "" {
|
if token == "" {
|
||||||
log.Fatalln("No $BOT_TOKEN given.")
|
log.Fatalln("no $BOT_TOKEN given")
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := session.New("Bot " + token)
|
s, err := session.New("Bot " + token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Session failed:", err)
|
log.Fatalln("session failed:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err := s.CurrentApplication()
|
app, err := s.CurrentApplication()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Failed to get application ID:", err)
|
log.Fatalln("failed to get application ID:", err)
|
||||||
}
|
}
|
||||||
appID := app.ID
|
appID := app.ID
|
||||||
|
|
||||||
s.AddHandler(func(e *gateway.InteractionCreateEvent) {
|
s.AddHandler(func(e *gateway.InteractionCreateEvent) {
|
||||||
if e.Type == discord.CommandInteraction {
|
var resp api.InteractionResponse
|
||||||
|
|
||||||
|
switch data := e.Data.(type) {
|
||||||
|
case discord.CommandInteraction:
|
||||||
|
if data.Name != "buttons" {
|
||||||
|
resp = api.InteractionResponse{
|
||||||
|
Type: api.MessageInteractionWithSource,
|
||||||
|
Data: &api.InteractionResponseData{
|
||||||
|
Content: option.NewNullableString("Unknown command: " + data.Name),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
// Send a message with a button back on slash commands.
|
// Send a message with a button back on slash commands.
|
||||||
data := api.InteractionResponse{
|
resp = api.InteractionResponse{
|
||||||
Type: api.MessageInteractionWithSource,
|
Type: api.MessageInteractionWithSource,
|
||||||
Data: &api.InteractionResponseData{
|
Data: &api.InteractionResponseData{
|
||||||
Content: option.NewNullableString("This is a message with a button!"),
|
Content: option.NewNullableString("This is a message with a button!"),
|
||||||
Components: &[]discord.Component{
|
Components: discord.ComponentsPtr(
|
||||||
&discord.ActionRowComponent{
|
discord.ActionRowComponent{
|
||||||
Components: []discord.Component{
|
discord.ButtonComponent{
|
||||||
&discord.ButtonComponent{
|
Label: "Hello World!",
|
||||||
Label: "Hello World!",
|
CustomID: "first_button",
|
||||||
CustomID: "first_button",
|
Emoji: &discord.ComponentEmoji{Name: "👋"},
|
||||||
Emoji: &discord.ButtonEmoji{
|
Style: discord.PrimaryButtonStyle(),
|
||||||
Name: "👋",
|
},
|
||||||
},
|
discord.ButtonComponent{
|
||||||
Style: discord.PrimaryButton,
|
Label: "Secondary",
|
||||||
},
|
CustomID: "second_button",
|
||||||
&discord.ButtonComponent{
|
Style: discord.SecondaryButtonStyle(),
|
||||||
Label: "Secondary",
|
},
|
||||||
CustomID: "second_button",
|
discord.ButtonComponent{
|
||||||
Style: discord.SecondaryButton,
|
Label: "Success",
|
||||||
},
|
CustomID: "success_button",
|
||||||
&discord.ButtonComponent{
|
Style: discord.SuccessButtonStyle(),
|
||||||
Label: "Success",
|
},
|
||||||
CustomID: "success_button",
|
discord.ButtonComponent{
|
||||||
Style: discord.SuccessButton,
|
Label: "Danger",
|
||||||
},
|
CustomID: "danger_button",
|
||||||
&discord.ButtonComponent{
|
Style: discord.DangerButtonStyle(),
|
||||||
Label: "Danger",
|
|
||||||
CustomID: "danger_button",
|
|
||||||
Style: discord.DangerButton,
|
|
||||||
},
|
|
||||||
&discord.ButtonComponent{
|
|
||||||
Label: "Link",
|
|
||||||
URL: "https://google.com",
|
|
||||||
Style: discord.LinkButton,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
// This is automatically put into its own row.
|
||||||
|
discord.ButtonComponent{
|
||||||
|
Label: "Link",
|
||||||
|
Style: discord.LinkButtonStyle("https://google.com"),
|
||||||
|
},
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case discord.ComponentInteraction:
|
||||||
if err := s.RespondInteraction(e.ID, e.Token, data); err != nil {
|
resp = api.InteractionResponse{
|
||||||
log.Println("failed to send interaction callback:", err)
|
Type: api.UpdateMessage,
|
||||||
|
Data: &api.InteractionResponseData{
|
||||||
|
Content: option.NewNullableString("Custom ID: " + string(data.ID())),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
default:
|
||||||
|
log.Printf("unknown interaction type %T", e.Data)
|
||||||
if e.Type != discord.ComponentInteraction {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
customID := e.Data.(*discord.ComponentInteractionData).CustomID
|
|
||||||
data := api.InteractionResponse{
|
|
||||||
Type: api.UpdateMessage,
|
|
||||||
Data: &api.InteractionResponseData{
|
|
||||||
Content: option.NewNullableString("Custom ID: " + customID),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.RespondInteraction(e.ID, e.Token, data); err != nil {
|
if err := s.RespondInteraction(e.ID, e.Token, resp); err != nil {
|
||||||
log.Println("failed to send interaction callback:", err)
|
log.Println("failed to send interaction callback:", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -125,6 +128,8 @@ func main() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("Creating guild commands...")
|
||||||
|
|
||||||
for _, command := range newCommands {
|
for _, command := range newCommands {
|
||||||
_, err := s.CreateGuildCommand(appID, guildID, command)
|
_, err := s.CreateGuildCommand(appID, guildID, command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -132,6 +137,8 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("Guild commands created. Bot is ready.")
|
||||||
|
|
||||||
// Block forever.
|
// Block forever.
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/diamondburned/arikawa/v3/api"
|
"github.com/diamondburned/arikawa/v3/api"
|
||||||
"github.com/diamondburned/arikawa/v3/discord"
|
"github.com/diamondburned/arikawa/v3/discord"
|
||||||
"github.com/diamondburned/arikawa/v3/gateway"
|
"github.com/diamondburned/arikawa/v3/gateway"
|
||||||
"github.com/diamondburned/arikawa/v3/session"
|
"github.com/diamondburned/arikawa/v3/state"
|
||||||
"github.com/diamondburned/arikawa/v3/utils/json/option"
|
"github.com/diamondburned/arikawa/v3/utils/json/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ func main() {
|
||||||
log.Fatalln("No $BOT_TOKEN given.")
|
log.Fatalln("No $BOT_TOKEN given.")
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := session.New("Bot " + token)
|
s, err := state.New("Bot " + token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Session failed:", err)
|
log.Fatalln("Session failed:", err)
|
||||||
return
|
return
|
||||||
|
@ -32,7 +32,6 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("Failed to get application ID:", err)
|
log.Fatalln("Failed to get application ID:", err)
|
||||||
}
|
}
|
||||||
appID := app.ID
|
|
||||||
|
|
||||||
s.AddHandler(func(e *gateway.InteractionCreateEvent) {
|
s.AddHandler(func(e *gateway.InteractionCreateEvent) {
|
||||||
data := api.InteractionResponse{
|
data := api.InteractionResponse{
|
||||||
|
@ -57,7 +56,7 @@ func main() {
|
||||||
|
|
||||||
log.Println("Gateway connected. Getting all guild commands.")
|
log.Println("Gateway connected. Getting all guild commands.")
|
||||||
|
|
||||||
commands, err := s.GuildCommands(appID, guildID)
|
commands, err := s.GuildCommands(app.ID, guildID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("failed to get guild commands:", err)
|
log.Fatalln("failed to get guild commands:", err)
|
||||||
}
|
}
|
||||||
|
@ -74,7 +73,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, command := range newCommands {
|
for _, command := range newCommands {
|
||||||
_, err := s.CreateGuildCommand(appID, guildID, command)
|
_, err := s.CreateGuildCommand(app.ID, guildID, command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("failed to create guild command:", err)
|
log.Fatalln("failed to create guild command:", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,11 @@ func (c *Client) CurrentApplication() (*discord.Application, error) {
|
||||||
|
|
||||||
// https://discord.com/developers/docs/interactions/slash-commands#create-global-application-command-json-params
|
// https://discord.com/developers/docs/interactions/slash-commands#create-global-application-command-json-params
|
||||||
type CreateCommandData struct {
|
type CreateCommandData struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Options []discord.CommandOption `json:"options,omitempty"`
|
Options discord.CommandOptions `json:"options,omitempty"`
|
||||||
NoDefaultPermission bool `json:"-"`
|
NoDefaultPermission bool `json:"-"`
|
||||||
Type discord.CommandType `json:"type,omitempty"`
|
Type discord.CommandType `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CreateCommandData) MarshalJSON() ([]byte, error) {
|
func (c CreateCommandData) MarshalJSON() ([]byte, error) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ type InteractionResponseData struct {
|
||||||
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
||||||
// Components is the list of components (such as buttons) to be attached to
|
// Components is the list of components (such as buttons) to be attached to
|
||||||
// the message.
|
// the message.
|
||||||
Components *[]discord.Component `json:"components,omitempty"`
|
Components *discord.ContainerComponents `json:"components,omitempty"`
|
||||||
// AllowedMentions are the allowed mentions for the message.
|
// AllowedMentions are the allowed mentions for the message.
|
||||||
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
||||||
// Flags are the interaction application command callback data flags.
|
// Flags are the interaction application command callback data flags.
|
||||||
|
@ -149,7 +149,7 @@ type EditInteractionResponseData struct {
|
||||||
// Embeds contains embedded rich content.
|
// Embeds contains embedded rich content.
|
||||||
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
||||||
// Components contains the new components to attach.
|
// Components contains the new components to attach.
|
||||||
Components *[]discord.Component `json:"components,omitempty"`
|
Components *discord.ContainerComponents `json:"components,omitempty"`
|
||||||
// AllowedMentions are the allowed mentions for the message.
|
// AllowedMentions are the allowed mentions for the message.
|
||||||
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
||||||
// Attachments are the attached files to keep.
|
// Attachments are the attached files to keep.
|
||||||
|
|
|
@ -287,7 +287,7 @@ type EditMessageData struct {
|
||||||
// Embeds contains embedded rich content.
|
// Embeds contains embedded rich content.
|
||||||
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
||||||
// Components contains the new components to attach.
|
// Components contains the new components to attach.
|
||||||
Components *[]discord.Component `json:"components,omitempty"`
|
Components *discord.ContainerComponents `json:"components,omitempty"`
|
||||||
// AllowedMentions are the allowed mentions for a message.
|
// AllowedMentions are the allowed mentions for a message.
|
||||||
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
||||||
// Attachments are the attached files to keep
|
// Attachments are the attached files to keep
|
||||||
|
|
|
@ -108,7 +108,7 @@ type SendMessageData struct {
|
||||||
Files []sendpart.File `json:"-"`
|
Files []sendpart.File `json:"-"`
|
||||||
// Components is the list of components (such as buttons) to be attached to
|
// Components is the list of components (such as buttons) to be attached to
|
||||||
// the message.
|
// the message.
|
||||||
Components []discord.Component `json:"components,omitempty"`
|
Components discord.ContainerComponents `json:"components,omitempty"`
|
||||||
|
|
||||||
// AllowedMentions are the allowed mentions for a message.
|
// AllowedMentions are the allowed mentions for a message.
|
||||||
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
AllowedMentions *AllowedMentions `json:"allowed_mentions,omitempty"`
|
||||||
|
|
|
@ -147,7 +147,7 @@ type ExecuteData struct {
|
||||||
|
|
||||||
// Components is the list of components (such as buttons) to be attached to
|
// Components is the list of components (such as buttons) to be attached to
|
||||||
// the message.
|
// the message.
|
||||||
Components []discord.Component `json:"components,omitempty"`
|
Components discord.ContainerComponents `json:"components,omitempty"`
|
||||||
|
|
||||||
// Files represents a list of files to upload. This will not be
|
// Files represents a list of files to upload. This will not be
|
||||||
// JSON-encoded and will only be available through WriteMultipart.
|
// JSON-encoded and will only be available through WriteMultipart.
|
||||||
|
@ -238,7 +238,7 @@ type EditMessageData struct {
|
||||||
// Embeds contains embedded rich content.
|
// Embeds contains embedded rich content.
|
||||||
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
Embeds *[]discord.Embed `json:"embeds,omitempty"`
|
||||||
// Components contains the new components to attach.
|
// Components contains the new components to attach.
|
||||||
Components *[]discord.Component `json:"components,omitempty"`
|
Components *discord.ContainerComponents `json:"components,omitempty"`
|
||||||
// AllowedMentions are the allowed mentions for a message.
|
// AllowedMentions are the allowed mentions for a message.
|
||||||
AllowedMentions *api.AllowedMentions `json:"allowed_mentions,omitempty"`
|
AllowedMentions *api.AllowedMentions `json:"allowed_mentions,omitempty"`
|
||||||
// Attachments are the attached files to keep
|
// Attachments are the attached files to keep
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
package discord
|
package discord
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v3/utils/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Application struct {
|
type Application struct {
|
||||||
// ID is the ID of the app.
|
// ID is the ID of the app.
|
||||||
ID AppID `json:"id"`
|
ID AppID `json:"id"`
|
||||||
// Name is the name of the app.
|
// Name is the name of the app.
|
||||||
Name string `json:"string"`
|
Name string `json:"name"`
|
||||||
// Icon is the icon hash of the app.
|
// Icon is the icon hash of the app.
|
||||||
Icon *Hash `json:"icon"`
|
Icon *Hash `json:"icon"`
|
||||||
// Description is the description of the app.
|
// Description is the description of the app.
|
||||||
Description string `json:"string"`
|
Description string `json:"description"`
|
||||||
// RPCOrigins is the RPC origin urls, if RPC is enabled.
|
// RPCOrigins is the RPC origin urls, if RPC is enabled.
|
||||||
RPCOrigins []string `json:"rpc_origins"`
|
RPCOrigins []string `json:"rpc_origins"`
|
||||||
// BotPublic is whether users besides the app owner can join the app's bot
|
// BotPublic is whether users besides the app owner can join the app's bot
|
||||||
|
@ -54,6 +48,7 @@ type Application struct {
|
||||||
// Slug is the URL slug that links to the game's store page.
|
// Slug is the URL slug that links to the game's store page.
|
||||||
Slug string `json:"slug"`
|
Slug string `json:"slug"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApplicationFlags uint32
|
type ApplicationFlags uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -96,158 +91,6 @@ const (
|
||||||
MembershipAccepted
|
MembershipAccepted
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command is the base "command" model that belongs to an application. This is
|
|
||||||
// what you are creating when you POST a new command.
|
|
||||||
//
|
|
||||||
// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-structure
|
|
||||||
type Command struct {
|
|
||||||
// ID is the unique id of the command.
|
|
||||||
ID CommandID `json:"id"`
|
|
||||||
// Type is the type of command.
|
|
||||||
Type CommandType `json:"type,omitempty"`
|
|
||||||
// AppID is the unique id of the parent application.
|
|
||||||
AppID AppID `json:"application_id"`
|
|
||||||
// GuildID is the guild id of the command, if not global.
|
|
||||||
GuildID GuildID `json:"guild_id,omitempty"`
|
|
||||||
// Name is the 1-32 lowercase character name matching ^[\w-]{1,32}$.
|
|
||||||
Name string `json:"name"`
|
|
||||||
// Description is the 1-100 character description.
|
|
||||||
Description string `json:"description"`
|
|
||||||
// Options are the parameters for the command.
|
|
||||||
//
|
|
||||||
// Note that required options must be listed before optional options, and
|
|
||||||
// a command, or each individual subcommand, can have a maximum of 25
|
|
||||||
// options.
|
|
||||||
//
|
|
||||||
// It is only present on ChatInputCommands.
|
|
||||||
Options []CommandOption `json:"options,omitempty"`
|
|
||||||
// NoDefaultPermissions defines whether the command is NOT enabled by
|
|
||||||
// default when the app is added to a guild.
|
|
||||||
NoDefaultPermission bool `json:"-"`
|
|
||||||
// Version is an autoincrementing version identifier updated during
|
|
||||||
// substantial record changes
|
|
||||||
Version Snowflake `json:"version,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandType uint
|
|
||||||
|
|
||||||
const (
|
|
||||||
ChatInputCommand CommandType = iota + 1
|
|
||||||
UserCommand
|
|
||||||
MessageCommand
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c Command) MarshalJSON() ([]byte, error) {
|
|
||||||
type RawCommand Command
|
|
||||||
cmd := struct {
|
|
||||||
RawCommand
|
|
||||||
DefaultPermission bool `json:"default_permission"`
|
|
||||||
}{RawCommand: RawCommand(c)}
|
|
||||||
|
|
||||||
// Discord defaults default_permission to true, so we need to invert the
|
|
||||||
// meaning of the field (>No<DefaultPermission) to match Go's default
|
|
||||||
// value, false.
|
|
||||||
cmd.DefaultPermission = !c.NoDefaultPermission
|
|
||||||
|
|
||||||
return json.Marshal(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Command) UnmarshalJSON(data []byte) error {
|
|
||||||
type RawCommand Command
|
|
||||||
cmd := struct {
|
|
||||||
*RawCommand
|
|
||||||
DefaultPermission bool `json:"default_permission"`
|
|
||||||
}{RawCommand: (*RawCommand)(c)}
|
|
||||||
if err := json.Unmarshal(data, &cmd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discord defaults default_permission to true, so we need to invert the
|
|
||||||
// meaning of the field (>No<DefaultPermission) to match Go's default
|
|
||||||
// value, false.
|
|
||||||
c.NoDefaultPermission = !cmd.DefaultPermission
|
|
||||||
|
|
||||||
// Discord defaults type to 1 if omitted.
|
|
||||||
if c.Type == 0 {
|
|
||||||
c.Type = ChatInputCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreatedAt returns a time object representing when the command was created.
|
|
||||||
func (c Command) CreatedAt() time.Time {
|
|
||||||
return c.ID.Time()
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandOption struct {
|
|
||||||
Type CommandOptionType `json:"type"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Required bool `json:"required"`
|
|
||||||
Choices []CommandOptionChoice `json:"choices,omitempty"`
|
|
||||||
Options []CommandOption `json:"options,omitempty"`
|
|
||||||
|
|
||||||
// If this option is a channel type, the channels shown will be restricted to these types
|
|
||||||
ChannelTypes []ChannelType `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandOption) MarshalJSON() ([]byte, error) {
|
|
||||||
type RawOption CommandOption
|
|
||||||
option := struct {
|
|
||||||
RawOption
|
|
||||||
ChannelTypes []uint16 `json:"channel_types,omitempty"`
|
|
||||||
}{RawOption: RawOption(c)}
|
|
||||||
|
|
||||||
// []uint8 is marshalled as a base64 string, so we marshal a []uint64 instead.
|
|
||||||
if len(c.ChannelTypes) > 0 {
|
|
||||||
option.ChannelTypes = make([]uint16, 0, len(c.ChannelTypes))
|
|
||||||
for _, t := range c.ChannelTypes {
|
|
||||||
option.ChannelTypes = append(option.ChannelTypes, uint16(t))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(option)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *CommandOption) UnmarshalJSON(data []byte) error {
|
|
||||||
type RawOption CommandOption
|
|
||||||
cmd := struct {
|
|
||||||
*RawOption
|
|
||||||
ChannelTypes []uint16 `json:"channel_types,omitempty"`
|
|
||||||
}{RawOption: (*RawOption)(c)}
|
|
||||||
if err := json.Unmarshal(data, &cmd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ChannelTypes = make([]ChannelType, 0, len(cmd.ChannelTypes))
|
|
||||||
for _, t := range cmd.ChannelTypes {
|
|
||||||
c.ChannelTypes = append(c.ChannelTypes, ChannelType(t))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandOptionType uint
|
|
||||||
|
|
||||||
const (
|
|
||||||
SubcommandOption CommandOptionType = iota + 1
|
|
||||||
SubcommandGroupOption
|
|
||||||
StringOption
|
|
||||||
IntegerOption
|
|
||||||
BooleanOption
|
|
||||||
UserOption
|
|
||||||
ChannelOption
|
|
||||||
RoleOption
|
|
||||||
MentionableOption
|
|
||||||
NumberOption
|
|
||||||
)
|
|
||||||
|
|
||||||
type CommandOptionChoice struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Value string `json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://discord.com/developers/docs/interactions/slash-commands#application-command-permissions-object-guild-application-command-permissions-structure
|
// https://discord.com/developers/docs/interactions/slash-commands#application-command-permissions-object-guild-application-command-permissions-structure
|
||||||
type GuildCommandPermissions struct {
|
type GuildCommandPermissions struct {
|
||||||
ID CommandID `json:"id"`
|
ID CommandID `json:"id"`
|
||||||
|
|
|
@ -144,9 +144,11 @@ func (ch Channel) IconURLWithType(t ImageType) string {
|
||||||
ch.ID.String() + "/" + t.format(ch.Icon)
|
ch.ID.String() + "/" + t.format(ch.Icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelType uint8
|
// ChannelType describes the type of the channel.
|
||||||
|
//
|
||||||
// https://discord.com/developers/docs/resources/channel#channel-object-channel-types
|
// https://discord.com/developers/docs/resources/channel#channel-object-channel-types
|
||||||
|
type ChannelType uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// GuildText is a text channel within a server.
|
// GuildText is a text channel within a server.
|
||||||
GuildText ChannelType = iota
|
GuildText ChannelType = iota
|
||||||
|
|
|
@ -0,0 +1,505 @@
|
||||||
|
package discord
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/diamondburned/arikawa/v3/utils/json"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandType is the type of the command, which describes the intended
|
||||||
|
// invokation source of the command.
|
||||||
|
type CommandType uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChatInputCommand CommandType = iota + 1
|
||||||
|
UserCommand
|
||||||
|
MessageCommand
|
||||||
|
)
|
||||||
|
|
||||||
|
// Command is the base "command" model that belongs to an application. This is
|
||||||
|
// what you are creating when you POST a new command.
|
||||||
|
//
|
||||||
|
// https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-structure
|
||||||
|
type Command struct {
|
||||||
|
// ID is the unique id of the command.
|
||||||
|
ID CommandID `json:"id"`
|
||||||
|
// Type is the intended source of the command.
|
||||||
|
Type CommandType `json:"type,omitempty"`
|
||||||
|
// AppID is the unique id of the parent application.
|
||||||
|
AppID AppID `json:"application_id"`
|
||||||
|
// GuildID is the guild id of the command, if not global.
|
||||||
|
GuildID GuildID `json:"guild_id,omitempty"`
|
||||||
|
// Name is the 1-32 lowercase character name matching ^[\w-]{1,32}$.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Description is the 1-100 character description.
|
||||||
|
Description string `json:"description"`
|
||||||
|
// Options are the parameters for the command. Its types are value types,
|
||||||
|
// which can either be a SubcommandOption or a SubcommandGroupOption.
|
||||||
|
//
|
||||||
|
// Note that required options must be listed before optional options, and
|
||||||
|
// a command, or each individual subcommand, can have a maximum of 25
|
||||||
|
// options.
|
||||||
|
//
|
||||||
|
// It is only present on ChatInputCommands.
|
||||||
|
Options CommandOptions `json:"options,omitempty"`
|
||||||
|
// NoDefaultPermissions defines whether the command is NOT enabled by
|
||||||
|
// default when the app is added to a guild.
|
||||||
|
NoDefaultPermission bool `json:"-"`
|
||||||
|
// Version is an autoincrementing version identifier updated during
|
||||||
|
// substantial record changes
|
||||||
|
Version Snowflake `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatedAt returns a time object representing when the command was created.
|
||||||
|
func (c *Command) CreatedAt() time.Time {
|
||||||
|
return c.ID.Time()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) MarshalJSON() ([]byte, error) {
|
||||||
|
type RawCommand Command
|
||||||
|
cmd := struct {
|
||||||
|
*RawCommand
|
||||||
|
DefaultPermission bool `json:"default_permission"`
|
||||||
|
}{RawCommand: (*RawCommand)(c)}
|
||||||
|
|
||||||
|
// Discord defaults default_permission to true, so we need to invert the
|
||||||
|
// meaning of the field (>No<DefaultPermission) to match Go's default
|
||||||
|
// value, false.
|
||||||
|
cmd.DefaultPermission = !c.NoDefaultPermission
|
||||||
|
|
||||||
|
return json.Marshal(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) UnmarshalJSON(data []byte) error {
|
||||||
|
type rawCommand Command
|
||||||
|
|
||||||
|
cmd := struct {
|
||||||
|
*rawCommand
|
||||||
|
DefaultPermission bool `json:"default_permission"`
|
||||||
|
}{
|
||||||
|
rawCommand: (*rawCommand)(c),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discord defaults default_permission to true, so we need to invert the
|
||||||
|
// meaning of the field (>No<DefaultPermission) to match Go's default
|
||||||
|
// value, false.
|
||||||
|
c.NoDefaultPermission = !cmd.DefaultPermission
|
||||||
|
|
||||||
|
// Discord defaults type to 1 if omitted.
|
||||||
|
if c.Type == 0 {
|
||||||
|
c.Type = ChatInputCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// commandTypeCheckError is returned if a one of Command's Options fails the
|
||||||
|
// type check.
|
||||||
|
type commandTypeCheckError struct {
|
||||||
|
name string
|
||||||
|
got interface{}
|
||||||
|
expect string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the erroneous command.
|
||||||
|
func (err commandTypeCheckError) Name() string {
|
||||||
|
return err.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data returns the erroneous data that belongs to this error. It is usually
|
||||||
|
// either a CommandOption or a CommandOptionValue.
|
||||||
|
func (err commandTypeCheckError) Data() interface{} {
|
||||||
|
return err.got
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error.
|
||||||
|
func (err commandTypeCheckError) Error() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"error at option name %q: expected %s, got %T",
|
||||||
|
err.name, err.expect, err.got,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandOptions is used primarily for unmarshaling.
|
||||||
|
type CommandOptions []CommandOption
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals b into these CommandOptions.
|
||||||
|
func (c *CommandOptions) UnmarshalJSON(b []byte) error {
|
||||||
|
var unknowns []UnknownCommandOption
|
||||||
|
if err := json.Unmarshal(b, &unknowns); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(unknowns) == 0 {
|
||||||
|
*c = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
*c = make([]CommandOption, len(unknowns))
|
||||||
|
for i, v := range unknowns {
|
||||||
|
(*c)[i] = v.data
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnknownCommandOption is used for unknown or unmarshaled CommandOption values.
|
||||||
|
// It is used in the unmarshaling stage for all CommandOption types.
|
||||||
|
//
|
||||||
|
// An UnknownCommandOption will satisfy both CommandOption and
|
||||||
|
// CommandOptionValue. Code that type-switches on either of them should not
|
||||||
|
// assume that only the expected types are used.
|
||||||
|
type UnknownCommandOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
OptionType CommandOptionType `json:"type"`
|
||||||
|
|
||||||
|
raw json.Raw
|
||||||
|
data CommandOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the supposeed name for this UnknownCommandOption.
|
||||||
|
func (u *UnknownCommandOption) Name() string {
|
||||||
|
return u.OptionName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns the supposed type for this UnknownCommandOption.
|
||||||
|
func (u *UnknownCommandOption) Type() CommandOptionType {
|
||||||
|
return u.OptionType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw returns the raw JSON of this UnknownCommandOption. It will only return a
|
||||||
|
// non-nil blob of JSON if the command option's type cannot be found. If this
|
||||||
|
// method doesn't return nil, then Data's type will be UnknownCommandOption.
|
||||||
|
func (u *UnknownCommandOption) Raw() json.Raw {
|
||||||
|
return u.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data returns the underlying data type, which is a type that satisfies either
|
||||||
|
// CommandOption or CommandOptionValue.
|
||||||
|
func (u *UnknownCommandOption) Data() CommandOption {
|
||||||
|
return u.data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement both CommandOption and CommandOptionValue.
|
||||||
|
func (u *UnknownCommandOption) _val() {}
|
||||||
|
|
||||||
|
// UnmarshalJSON parses the JSON into the struct as-is then reads all its
|
||||||
|
// children Options/Choices (if subcommand(group)). Typed command options are
|
||||||
|
// created into u.Data, or u.Raw if the type is unknown. This is done from the
|
||||||
|
// bottom up.
|
||||||
|
func (u *UnknownCommandOption) UnmarshalJSON(b []byte) error {
|
||||||
|
type unknown UnknownCommandOption
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, (*unknown)(u)); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to unmarshal unknown")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch u.Type() {
|
||||||
|
case SubcommandOptionType:
|
||||||
|
u.data = &SubcommandOption{}
|
||||||
|
case SubcommandGroupOptionType:
|
||||||
|
u.data = &SubcommandGroupOption{}
|
||||||
|
case StringOptionType:
|
||||||
|
u.data = &StringOption{}
|
||||||
|
case IntegerOptionType:
|
||||||
|
u.data = &IntegerOption{}
|
||||||
|
case BooleanOptionType:
|
||||||
|
u.data = &BooleanOption{}
|
||||||
|
case UserOptionType:
|
||||||
|
u.data = &UserOption{}
|
||||||
|
case ChannelOptionType:
|
||||||
|
u.data = &ChannelOption{}
|
||||||
|
case RoleOptionType:
|
||||||
|
u.data = &RoleOption{}
|
||||||
|
case MentionableOptionType:
|
||||||
|
u.data = &MentionableOption{}
|
||||||
|
case NumberOptionType:
|
||||||
|
u.data = &NumberOption{}
|
||||||
|
default:
|
||||||
|
// Copy the blob of bytes into a new slice.
|
||||||
|
u.raw = append(json.Raw(nil), b...)
|
||||||
|
u.data = u
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, u.data); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to unmarshal type %d", u.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandOptionType is the enumerated integer type for command options. The
|
||||||
|
// user usually won't have to touch any of these enum constants.
|
||||||
|
type CommandOptionType uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
SubcommandOptionType CommandOptionType = iota + 1
|
||||||
|
SubcommandGroupOptionType
|
||||||
|
StringOptionType
|
||||||
|
IntegerOptionType
|
||||||
|
BooleanOptionType
|
||||||
|
UserOptionType
|
||||||
|
ChannelOptionType
|
||||||
|
RoleOptionType
|
||||||
|
MentionableOptionType
|
||||||
|
NumberOptionType
|
||||||
|
maxOptionType // for bound checking
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandOption is a union of command option types. The constructors for
|
||||||
|
// CommandOption will hint the types that can be a CommandOption.
|
||||||
|
type CommandOption interface {
|
||||||
|
Name() string
|
||||||
|
Type() CommandOptionType
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maintaining these structs is quite an effort. If a new field is added into
|
||||||
|
// the generic CommandOption type, you MUST update ALL CommandOption structs.
|
||||||
|
// This means copy-pasting, yes.
|
||||||
|
|
||||||
|
// SubcommandGroupOption is a subcommand group that fits into a CommandOption.
|
||||||
|
type SubcommandGroupOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Subcommands []*SubcommandOption `json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (s *SubcommandGroupOption) Name() string { return s.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOption.
|
||||||
|
func (s *SubcommandGroupOption) Type() CommandOptionType { return SubcommandGroupOptionType }
|
||||||
|
|
||||||
|
// SubcommandOption is a subcommand option that fits into a CommandOption.
|
||||||
|
type SubcommandOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
// Options contains command option values. All CommandOption types except
|
||||||
|
// for SubcommandOption and SubcommandGroupOption will implement this
|
||||||
|
// interface.
|
||||||
|
Options []CommandOptionValue `json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (s *SubcommandOption) Name() string { return s.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOption.
|
||||||
|
func (s *SubcommandOption) Type() CommandOptionType { return SubcommandOptionType }
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals the given JSON bytes. It actually does
|
||||||
|
// type-checking.
|
||||||
|
func (s *SubcommandOption) UnmarshalJSON(b []byte) error {
|
||||||
|
type raw SubcommandOption
|
||||||
|
|
||||||
|
var opt struct {
|
||||||
|
*raw
|
||||||
|
Type CommandOptionType `json:"type"`
|
||||||
|
Options []UnknownCommandOption `json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.raw = (*raw)(s)
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &opt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.Type != SubcommandOptionType {
|
||||||
|
return fmt.Errorf("unexpected (not SubcommandOption) type %d", s.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Options = make([]CommandOptionValue, len(opt.Options))
|
||||||
|
for i, opt := range opt.Options {
|
||||||
|
ov, ok := opt.data.(CommandOptionValue)
|
||||||
|
if !ok {
|
||||||
|
return commandTypeCheckError{opt.OptionName, opt.data, "CommandOptionValue"}
|
||||||
|
}
|
||||||
|
s.Options[i] = ov
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandOptionValue is a subcommand option that fits into a subcommand.
|
||||||
|
type CommandOptionValue interface {
|
||||||
|
CommandOption
|
||||||
|
_val()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type StringOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []StringChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (s *StringOption) Name() string { return s.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (s *StringOption) Type() CommandOptionType { return StringOptionType }
|
||||||
|
func (s *StringOption) _val() {}
|
||||||
|
|
||||||
|
// StringChoice is a pair of string key to a string.
|
||||||
|
type StringChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntegerOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type IntegerOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []IntegerChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (i *IntegerOption) Name() string { return i.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (i *IntegerOption) Type() CommandOptionType { return IntegerOptionType }
|
||||||
|
func (i *IntegerOption) _val() {}
|
||||||
|
|
||||||
|
// IntegerChoice is a pair of string key to an integer.
|
||||||
|
type IntegerChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value int `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BooleanOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type BooleanOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []BooleanChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (b *BooleanOption) Name() string { return b.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (b *BooleanOption) Type() CommandOptionType { return BooleanOptionType }
|
||||||
|
func (b *BooleanOption) _val() {}
|
||||||
|
|
||||||
|
// BooleanChoice is a pair of string key to a boolean.
|
||||||
|
type BooleanChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value bool `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type UserOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []UserChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (u *UserOption) Name() string { return u.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (u *UserOption) Type() CommandOptionType { return UserOptionType }
|
||||||
|
func (u *UserOption) _val() {}
|
||||||
|
|
||||||
|
// UserChoice is a pair of string key to a user ID.
|
||||||
|
type UserChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value UserID `json:"value,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChannelOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type ChannelOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []ChannelChoice `json:"choices,omitempty"`
|
||||||
|
ChannelTypes []ChannelType `json:"channel_types,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (c *ChannelOption) Name() string { return c.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (c *ChannelOption) Type() CommandOptionType { return ChannelOptionType }
|
||||||
|
func (c *ChannelOption) _val() {}
|
||||||
|
|
||||||
|
// ChannelChoice is a pair of string key to a channel ID.
|
||||||
|
type ChannelChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value ChannelID `json:"value,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type RoleOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []RoleChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (r *RoleOption) Name() string { return r.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (r *RoleOption) Type() CommandOptionType { return RoleOptionType }
|
||||||
|
func (r *RoleOption) _val() {}
|
||||||
|
|
||||||
|
// RoleChoice is a pair of string key to a role ID.
|
||||||
|
type RoleChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value RoleID `json:"value,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MentionableOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type MentionableOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []MentionableChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (m *MentionableOption) Name() string { return m.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (m *MentionableOption) Type() CommandOptionType { return MentionableOptionType }
|
||||||
|
func (m *MentionableOption) _val() {}
|
||||||
|
|
||||||
|
// MentionableChoice is a pair of string key to a mentionable snowflake IDs. To
|
||||||
|
// use this correctly, use the Resolved field.
|
||||||
|
type MentionableChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value Snowflake `json:"value,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumberOption is a subcommand option that fits into a CommandOptionValue.
|
||||||
|
type NumberOption struct {
|
||||||
|
OptionName string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Choices []NumberChoice `json:"choices,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements CommandOption.
|
||||||
|
func (n *NumberOption) Name() string { return n.OptionName }
|
||||||
|
|
||||||
|
// Type implements CommandOptionValue.
|
||||||
|
func (n *NumberOption) Type() CommandOptionType { return NumberOptionType }
|
||||||
|
func (n *NumberOption) _val() {}
|
||||||
|
|
||||||
|
// NumberChoice is a pair of string key to a float64 values.
|
||||||
|
type NumberChoice struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value float64 `json:"value"`
|
||||||
|
}
|
|
@ -1,246 +1,455 @@
|
||||||
package discord
|
package discord
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"fmt"
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v3/utils/json"
|
"github.com/diamondburned/arikawa/v3/utils/json"
|
||||||
"github.com/diamondburned/arikawa/v3/utils/json/option"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNestedActionRow = errors.New("action row cannot have action row as a child")
|
|
||||||
|
|
||||||
// ComponentType is the type of a component.
|
// ComponentType is the type of a component.
|
||||||
type ComponentType uint
|
type ComponentType uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ActionRowComponentType ComponentType = iota + 1
|
_ ComponentType = iota
|
||||||
|
ActionRowComponentType
|
||||||
ButtonComponentType
|
ButtonComponentType
|
||||||
SelectComponentType
|
SelectComponentType
|
||||||
)
|
)
|
||||||
|
|
||||||
// ComponentWrap wraps Component for the purpose of JSON unmarshalling.
|
// String formats Type's name as a string.
|
||||||
// Type assertions should be made on Component to access the underlying data.
|
func (t ComponentType) String() string {
|
||||||
// The underlying types of the Component are pointer types.
|
switch t {
|
||||||
type ComponentWrap struct {
|
|
||||||
Component Component
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnwrapComponents returns a slice of the underlying component interfaces.
|
|
||||||
func UnwrapComponents(wraps []ComponentWrap) []Component {
|
|
||||||
components := make([]Component, len(wraps))
|
|
||||||
for i, w := range wraps {
|
|
||||||
components[i] = w.Component
|
|
||||||
}
|
|
||||||
|
|
||||||
return components
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the underlying component's type.
|
|
||||||
func (c *ComponentWrap) Type() ComponentType {
|
|
||||||
return c.Component.Type()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON marshals the component in the format Discord expects.
|
|
||||||
func (c *ComponentWrap) MarshalJSON() ([]byte, error) {
|
|
||||||
return c.Component.MarshalJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals json into the component.
|
|
||||||
func (c *ComponentWrap) UnmarshalJSON(b []byte) error {
|
|
||||||
var t struct {
|
|
||||||
Type ComponentType `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
err := json.Unmarshal(b, &t)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.Type {
|
|
||||||
case ActionRowComponentType:
|
case ActionRowComponentType:
|
||||||
c.Component = &ActionRowComponent{}
|
return "ActionRow"
|
||||||
case ButtonComponentType:
|
case ButtonComponentType:
|
||||||
c.Component = &ButtonComponent{}
|
return "Button"
|
||||||
|
case SelectComponentType:
|
||||||
|
return "Select"
|
||||||
default:
|
default:
|
||||||
c.Component = &UnknownComponent{typ: t.Type}
|
return fmt.Sprintf("ComponentType(%d)", int(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Unmarshal(b, c.Component)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component is a component that can be attached to an interaction response.
|
// ContainerComponents is primarily used for unmarshaling. It is the top-level
|
||||||
type Component interface {
|
// type for component lists.
|
||||||
json.Marshaler
|
type ContainerComponents []ContainerComponent
|
||||||
Type() ComponentType
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActionRowComponent is a row of components at the bottom of a message.
|
// UnmarshalJSON unmarshals JSON into the component. It does type-checking and
|
||||||
type ActionRowComponent struct {
|
// will only accept container components.
|
||||||
Components []Component `json:"components"`
|
func (c *ContainerComponents) UnmarshalJSON(b []byte) error {
|
||||||
}
|
var jsons []json.Raw
|
||||||
|
if err := json.Unmarshal(b, &jsons); err != nil {
|
||||||
// Type implements the Component interface.
|
|
||||||
func (*ActionRowComponent) Type() ComponentType {
|
|
||||||
return ActionRowComponentType
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON marshals the action row in the format Discord expects.
|
|
||||||
func (a ActionRowComponent) MarshalJSON() ([]byte, error) {
|
|
||||||
type actionRow ActionRowComponent
|
|
||||||
|
|
||||||
return json.Marshal(struct {
|
|
||||||
actionRow
|
|
||||||
Type ComponentType `json:"type"`
|
|
||||||
}{
|
|
||||||
actionRow: actionRow(a),
|
|
||||||
Type: ActionRowComponentType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals json into the components.
|
|
||||||
func (a *ActionRowComponent) UnmarshalJSON(b []byte) error {
|
|
||||||
type actionRow ActionRowComponent
|
|
||||||
|
|
||||||
type rowTypes struct {
|
|
||||||
Components []struct {
|
|
||||||
Type ComponentType `json:"type"`
|
|
||||||
} `json:"components"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var r rowTypes
|
|
||||||
err := json.Unmarshal(b, &r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Components = make([]Component, len(r.Components))
|
*c = make([]ContainerComponent, len(jsons))
|
||||||
for i, t := range r.Components {
|
|
||||||
switch t.Type {
|
for i, b := range jsons {
|
||||||
case ActionRowComponentType:
|
p, err := ParseComponent(b)
|
||||||
// ActionRow cannot have child components of type Actionrow
|
if err != nil {
|
||||||
return ErrNestedActionRow
|
return err
|
||||||
case ButtonComponentType:
|
|
||||||
a.Components[i] = &ButtonComponent{}
|
|
||||||
default:
|
|
||||||
a.Components[i] = &UnknownComponent{typ: t.Type}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
alias := actionRow(*a)
|
cc, ok := p.(ContainerComponent)
|
||||||
err = json.Unmarshal(b, &alias)
|
if !ok {
|
||||||
if err != nil {
|
return fmt.Errorf("expected container, got %T", p)
|
||||||
return err
|
}
|
||||||
|
(*c)[i] = cc
|
||||||
}
|
}
|
||||||
|
|
||||||
*a = ActionRowComponent(alias)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ButtonComponent is a clickable button that may be added to an interaction
|
// Component is a component that can be attached to an interaction response. A
|
||||||
// response.
|
// Component is either an InteractiveComponent or a ContainerComponent. See
|
||||||
type ButtonComponent struct {
|
// those appropriate types for more information.
|
||||||
Label string `json:"label"`
|
type Component interface {
|
||||||
// CustomID attached to InteractionCreate event when clicked.
|
// Type returns the type of the underlying component.
|
||||||
CustomID string `json:"custom_id"`
|
Type() ComponentType
|
||||||
Style ButtonStyle `json:"style"`
|
_cmp()
|
||||||
Emoji *ButtonEmoji `json:"emoji,omitempty"`
|
}
|
||||||
// URL is only present on link-style buttons.
|
|
||||||
URL URL `json:"url,omitempty"`
|
// InteractiveComponent extends the Component for components that are
|
||||||
Disabled bool `json:"disabled,omitempty"`
|
// interactible, or components that aren't containers (like ActionRow). This is
|
||||||
|
// useful for ActionRow to type-check that no nested ActionRows are allowed.
|
||||||
|
type InteractiveComponent interface {
|
||||||
|
Component
|
||||||
|
// ID returns the ID of the underlying component.
|
||||||
|
ID() ComponentID
|
||||||
|
_icp()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerComponent is the opposite of InteractiveComponent: it describes
|
||||||
|
// components that only contain other components. The only component that
|
||||||
|
// satisfies that is ActionRow.
|
||||||
|
type ContainerComponent interface {
|
||||||
|
Component
|
||||||
|
_ctn()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewComponent returns a new Component from the given type that's matched with
|
||||||
|
// the global ComponentFunc map. If the type is unknown, then Unknown is used.
|
||||||
|
func ParseComponent(b []byte) (Component, error) {
|
||||||
|
var t struct {
|
||||||
|
Type ComponentType
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &t); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to unmarshal component type")
|
||||||
|
}
|
||||||
|
|
||||||
|
var c Component
|
||||||
|
|
||||||
|
switch t.Type {
|
||||||
|
case ActionRowComponentType:
|
||||||
|
c = &ActionRowComponent{}
|
||||||
|
case ButtonComponentType:
|
||||||
|
c = &ButtonComponent{}
|
||||||
|
case SelectComponentType:
|
||||||
|
c = &SelectComponent{}
|
||||||
|
default:
|
||||||
|
c = &UnknownComponent{typ: t.Type}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, c); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to unmarshal component body")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionRow is a row of components at the bottom of a message. Its type,
|
||||||
|
// InteractiveComponent, ensures that only non-ActionRow components are allowed
|
||||||
|
// on it.
|
||||||
|
type ActionRowComponent []InteractiveComponent
|
||||||
|
|
||||||
|
// Components wraps the given list of components inside ActionRows if it's not
|
||||||
|
// already in one. This is a convenient function that wraps components inside
|
||||||
|
// ActionRows for the user. It panics if any of the action rows have nested
|
||||||
|
// action rows in them.
|
||||||
|
//
|
||||||
|
// Here's an example of how to use it:
|
||||||
|
//
|
||||||
|
// discord.Components(
|
||||||
|
// discord.TextButtonComponent("Hello, world!"),
|
||||||
|
// discord.Components(
|
||||||
|
// discord.TextButtonComponent("Hello!"),
|
||||||
|
// discord.TextButtonComponent("Delete."),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
func Components(components ...Component) ContainerComponents {
|
||||||
|
new := make([]ContainerComponent, len(components))
|
||||||
|
|
||||||
|
for i, comp := range components {
|
||||||
|
cc, ok := comp.(ContainerComponent)
|
||||||
|
if !ok {
|
||||||
|
// Wrap. We're asserting that comp is either a ContainerComponent or
|
||||||
|
// an InteractiveComponent. Neither would be a bug, therefore panic.
|
||||||
|
cc = &ActionRowComponent{comp.(InteractiveComponent)}
|
||||||
|
}
|
||||||
|
|
||||||
|
new[i] = cc
|
||||||
|
}
|
||||||
|
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComponentsPtr returns the pointer to Components' return. This is a
|
||||||
|
// convenient function.
|
||||||
|
func ComponentsPtr(components ...Component) *ContainerComponents {
|
||||||
|
v := Components(components...)
|
||||||
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type implements the Component interface.
|
// Type implements the Component interface.
|
||||||
func (*ButtonComponent) Type() ComponentType {
|
func (a *ActionRowComponent) Type() ComponentType {
|
||||||
return ButtonComponentType
|
return ActionRowComponentType
|
||||||
}
|
}
|
||||||
|
|
||||||
// ButtonStyle is the style to display a button in.
|
func (a *ActionRowComponent) _cmp() {}
|
||||||
type ButtonStyle uint
|
func (a *ActionRowComponent) _ctn() {}
|
||||||
|
|
||||||
// All types of ButtonStyle documented.
|
// MarshalJSON marshals the action row in the format Discord expects.
|
||||||
const (
|
func (a *ActionRowComponent) MarshalJSON() ([]byte, error) {
|
||||||
// PrimaryButton is a blurple button.
|
var actionRow struct {
|
||||||
PrimaryButton ButtonStyle = iota + 1
|
Type ComponentType `json:"type"`
|
||||||
// SecondaryButton is a grey button.
|
Components *[]InteractiveComponent `json:"components"`
|
||||||
SecondaryButton
|
}
|
||||||
// SuccessButton is a green button.
|
|
||||||
SuccessButton
|
|
||||||
// DangerButton is a red button.
|
|
||||||
DangerButton
|
|
||||||
// LinkButton is a button that navigates to a URL.
|
|
||||||
LinkButton
|
|
||||||
)
|
|
||||||
|
|
||||||
// ButtonEmoji is the emoji displayed on the button before the text.
|
actionRow.Components = (*[]InteractiveComponent)(a)
|
||||||
type ButtonEmoji struct {
|
actionRow.Type = a.Type()
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
|
return json.Marshal(actionRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals JSON into the components. It does type-checking and
|
||||||
|
// will only accept interactive components.
|
||||||
|
func (a *ActionRowComponent) UnmarshalJSON(b []byte) error {
|
||||||
|
var row struct {
|
||||||
|
Components []json.Raw `json:"components"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &row); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*a = make(ActionRowComponent, len(row.Components))
|
||||||
|
|
||||||
|
for i, b := range row.Components {
|
||||||
|
p, err := ParseComponent(b)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to parse component %d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
ic, ok := p.(InteractiveComponent)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("expected interactive, got %T", p)
|
||||||
|
}
|
||||||
|
(*a)[i] = ic
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComponentID is the type for a component's custom ID. It is NOT a snowflake,
|
||||||
|
// but rather a user-defined opaque string.
|
||||||
|
type ComponentID string
|
||||||
|
|
||||||
|
// ComponentEmoji is the emoji displayed on the button before the text. For more
|
||||||
|
// information, see Emoji.
|
||||||
|
type ComponentEmoji struct {
|
||||||
ID EmojiID `json:"id,omitempty"`
|
ID EmojiID `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
Animated bool `json:"animated,omitempty"`
|
Animated bool `json:"animated,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON marshals the button in the format Discord expects.
|
// ButtonComponentStyle is the style to display a button in. Use one of the
|
||||||
func (b ButtonComponent) MarshalJSON() ([]byte, error) {
|
// ButtonStyle constructor functions.
|
||||||
type button ButtonComponent
|
type ButtonComponentStyle interface {
|
||||||
|
style() int
|
||||||
if b.Style == 0 {
|
|
||||||
b.Style = PrimaryButton // Sane default for button.
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(struct {
|
|
||||||
button
|
|
||||||
Type ComponentType `json:"type"`
|
|
||||||
}{
|
|
||||||
button: button(b),
|
|
||||||
Type: ButtonComponentType,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectComponent is a clickable button that may be added to an interaction
|
type basicButtonStyle int
|
||||||
|
|
||||||
|
func (s basicButtonStyle) style() int { return int(s) }
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ basicButtonStyle = iota
|
||||||
|
primaryButtonStyle
|
||||||
|
secondaryButtonStyle
|
||||||
|
successButtonStyle
|
||||||
|
dangerButtonStyle
|
||||||
|
linkButtonStyleNum
|
||||||
|
basicButtonStyleLen
|
||||||
|
)
|
||||||
|
|
||||||
|
// PrimaryButtonStyle is a style for a blurple button.
|
||||||
|
func PrimaryButtonStyle() ButtonComponentStyle { return primaryButtonStyle }
|
||||||
|
|
||||||
|
// SecondaryButtonStyle is a style for a grey button.
|
||||||
|
func SecondaryButtonStyle() ButtonComponentStyle { return secondaryButtonStyle }
|
||||||
|
|
||||||
|
// SuccessButtonStyle is a style for a green button.
|
||||||
|
func SuccessButtonStyle() ButtonComponentStyle { return successButtonStyle }
|
||||||
|
|
||||||
|
// DangerButtonStyle is a style for a red button.
|
||||||
|
func DangerButtonStyle() ButtonComponentStyle { return dangerButtonStyle }
|
||||||
|
|
||||||
|
type linkButtonStyle URL
|
||||||
|
|
||||||
|
func (s linkButtonStyle) style() int { return int(linkButtonStyleNum) }
|
||||||
|
|
||||||
|
// LinkButtonStyle is a button style that navigates to a URL.
|
||||||
|
func LinkButtonStyle(url URL) ButtonComponentStyle { return linkButtonStyle(url) }
|
||||||
|
|
||||||
|
// Button is a clickable button that may be added to an interaction
|
||||||
// response.
|
// response.
|
||||||
type SelectComponent struct {
|
type ButtonComponent struct {
|
||||||
CustomID string `json:"custom_id"`
|
// Style is one of the button styles.
|
||||||
Options []SelectComponentOption `json:"options"`
|
Style ButtonComponentStyle `json:"style"`
|
||||||
Placeholder string `json:"placeholder,omitempty"`
|
// CustomID attached to InteractionCreate event when clicked.
|
||||||
MinValues option.Int `json:"min_values,omitempty"`
|
CustomID ComponentID `json:"custom_id,omitempty"`
|
||||||
MaxValues int `json:"max_values,omitempty"`
|
// Label is the text that appears on the button. It can have maximum 100
|
||||||
Disabled bool `json:"disabled,omitempty"`
|
// characters.
|
||||||
|
Label string `json:"label,omitempty"`
|
||||||
|
// Emoji should have Name, ID and Animated filled.
|
||||||
|
Emoji *ComponentEmoji `json:"emoji,omitempty"`
|
||||||
|
// Disabled determines whether the button is disabled.
|
||||||
|
Disabled bool `json:"disabled,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SelectComponentOption struct {
|
// TextButtonComponent creates a new button with the given label used for the label and
|
||||||
Label string `json:"label"`
|
// the custom ID.
|
||||||
Value string `json:"value"`
|
func TextButtonComponent(style ButtonComponentStyle, label string) ButtonComponent {
|
||||||
Description string `json:"description,omitempty"`
|
return ButtonComponent{
|
||||||
Emoji *ButtonEmoji `json:"emoji,omitempty"`
|
Style: style,
|
||||||
Default bool `json:"default,omitempty"`
|
Label: label,
|
||||||
|
CustomID: ComponentID(label),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ID implements the Component interface.
|
||||||
|
func (b *ButtonComponent) ID() ComponentID { return b.CustomID }
|
||||||
|
|
||||||
// Type implements the Component interface.
|
// Type implements the Component interface.
|
||||||
func (*SelectComponent) Type() ComponentType {
|
func (b *ButtonComponent) Type() ComponentType {
|
||||||
|
return ButtonComponentType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *ButtonComponent) _cmp() {}
|
||||||
|
func (b *ButtonComponent) _icp() {}
|
||||||
|
|
||||||
|
// MarshalJSON marshals the button in the format Discord expects.
|
||||||
|
func (b *ButtonComponent) MarshalJSON() ([]byte, error) {
|
||||||
|
if b.Style == nil {
|
||||||
|
b.Style = PrimaryButtonStyle() // Sane default for button.
|
||||||
|
}
|
||||||
|
|
||||||
|
type button ButtonComponent
|
||||||
|
|
||||||
|
type Msg struct {
|
||||||
|
*button
|
||||||
|
Type ComponentType `json:"type"`
|
||||||
|
Style int `json:"style"`
|
||||||
|
URL URL `json:"url,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := Msg{
|
||||||
|
Type: ButtonComponentType,
|
||||||
|
Style: b.Style.style(),
|
||||||
|
button: (*button)(b),
|
||||||
|
}
|
||||||
|
|
||||||
|
if link, ok := b.Style.(linkButtonStyle); ok {
|
||||||
|
msg.URL = URL(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals a component JSON into the button. It does NOT do
|
||||||
|
// type-checking; use ParseComponent for that.
|
||||||
|
func (b *ButtonComponent) UnmarshalJSON(j []byte) error {
|
||||||
|
type button ButtonComponent
|
||||||
|
|
||||||
|
msg := struct {
|
||||||
|
*button
|
||||||
|
Style basicButtonStyle `json:"style"`
|
||||||
|
URL URL `json:"url,omitempty"`
|
||||||
|
}{
|
||||||
|
button: (*button)(b),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(j, &msg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 > msg.Style || msg.Style >= basicButtonStyleLen {
|
||||||
|
return fmt.Errorf("unknown button style %d", msg.Style)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch msg.Style {
|
||||||
|
case linkButtonStyleNum:
|
||||||
|
b.Style = LinkButtonStyle(msg.URL)
|
||||||
|
default:
|
||||||
|
b.Style = msg.Style
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select is a clickable button that may be added to an interaction
|
||||||
|
// response.
|
||||||
|
type SelectComponent struct {
|
||||||
|
// Options are the choices in the select.
|
||||||
|
Options []SelectOption `json:"options"`
|
||||||
|
// CustomID is the custom unique ID.
|
||||||
|
CustomID ComponentID `json:"custom_id,omitempty"`
|
||||||
|
// Placeholder is the custom placeholder text if nothing is selected. Max
|
||||||
|
// 100 characters.
|
||||||
|
Placeholder string `json:"placeholder,omitempty"`
|
||||||
|
// ValueLimits is the minimum and maximum number of items that can be
|
||||||
|
// chosen. The default is [1, 1] if ValueLimits is a zero-value.
|
||||||
|
ValueLimits [2]int `json:"-"`
|
||||||
|
// Disabled disables the select if true.
|
||||||
|
Disabled bool `json:"disabled,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectOption is an option in the select component.
|
||||||
|
type SelectOption struct {
|
||||||
|
// Label is the user-facing name of the option. Max 100 characters.
|
||||||
|
Label string `json:"label"`
|
||||||
|
// Value is the internal value that is echoed back to the program. It's
|
||||||
|
// similar to the custom ID. Max 100 characters.
|
||||||
|
Value string `json:"value"`
|
||||||
|
// Description is the additional description of an option.
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
// Emoji is the optional emoji object.
|
||||||
|
Emoji *ComponentEmoji `json:"emoji,omitempty"`
|
||||||
|
// Default will render this option as selected by default if true.
|
||||||
|
Default bool `json:"default,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID implements the Component interface.
|
||||||
|
func (s *SelectComponent) ID() ComponentID { return s.CustomID }
|
||||||
|
|
||||||
|
// Type implements the Component interface.
|
||||||
|
func (s *SelectComponent) Type() ComponentType {
|
||||||
return SelectComponentType
|
return SelectComponentType
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON marshals the select in the format Discord expects.
|
func (s *SelectComponent) _cmp() {}
|
||||||
func (s SelectComponent) MarshalJSON() ([]byte, error) {
|
func (s *SelectComponent) _icp() {}
|
||||||
type selectComponent SelectComponent
|
|
||||||
|
|
||||||
return json.Marshal(struct {
|
// MarshalJSON marshals the select in the format Discord expects.
|
||||||
selectComponent
|
func (s *SelectComponent) MarshalJSON() ([]byte, error) {
|
||||||
|
type sel SelectComponent
|
||||||
|
|
||||||
|
type Msg struct {
|
||||||
Type ComponentType `json:"type"`
|
Type ComponentType `json:"type"`
|
||||||
}{
|
*sel
|
||||||
selectComponent: selectComponent(s),
|
MinValues *int `json:"min_values,omitempty"`
|
||||||
Type: SelectComponentType,
|
MaxValues *int `json:"max_values,omitempty"`
|
||||||
})
|
}
|
||||||
|
|
||||||
|
msg := Msg{
|
||||||
|
Type: SelectComponentType,
|
||||||
|
sel: (*sel)(s),
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.ValueLimits != [2]int{0, 0} {
|
||||||
|
msg.MinValues = new(int)
|
||||||
|
msg.MaxValues = new(int)
|
||||||
|
|
||||||
|
*msg.MinValues = s.ValueLimits[0]
|
||||||
|
*msg.MaxValues = s.ValueLimits[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnknownComponent is reserved for components with unknown or not yet
|
// Unknown is reserved for components with unknown or not yet implemented
|
||||||
// implemented components types.
|
// components types. It can also be used in place of a ComponentInteraction.
|
||||||
type UnknownComponent struct {
|
type UnknownComponent struct {
|
||||||
json.Raw
|
json.Raw
|
||||||
|
id ComponentID
|
||||||
typ ComponentType
|
typ ComponentType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type implements the Component interface.
|
// ID implements the Component and ComponentInteraction interfaces.
|
||||||
func (u *UnknownComponent) Type() ComponentType {
|
func (u *UnknownComponent) ID() ComponentID { return u.id }
|
||||||
return u.typ
|
|
||||||
|
// Type implements the Component and ComponentInteraction interfaces.
|
||||||
|
func (u *UnknownComponent) Type() ComponentType { return u.typ }
|
||||||
|
|
||||||
|
// Type implements InteractionData.
|
||||||
|
func (u *UnknownComponent) InteractionType() InteractionDataType {
|
||||||
|
return ComponentInteractionType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UnknownComponent) resp() {}
|
||||||
|
func (u *UnknownComponent) data() {}
|
||||||
|
func (u *UnknownComponent) _cmp() {}
|
||||||
|
func (u *UnknownComponent) _icp() {}
|
||||||
|
|
|
@ -4,14 +4,17 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/diamondburned/arikawa/v3/utils/json"
|
"github.com/diamondburned/arikawa/v3/utils/json"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// InteractionEvent describes the full incoming interaction event. It may be a
|
||||||
|
// gateway event or a webhook event.
|
||||||
|
//
|
||||||
// https://discord.com/developers/docs/topics/gateway#interactions
|
// https://discord.com/developers/docs/topics/gateway#interactions
|
||||||
type Interaction struct {
|
type InteractionEvent struct {
|
||||||
ID InteractionID `json:"id"`
|
ID InteractionID `json:"id"`
|
||||||
|
Data InteractionData `json:"data"`
|
||||||
AppID AppID `json:"application_id"`
|
AppID AppID `json:"application_id"`
|
||||||
Type InteractionType `json:"type"`
|
|
||||||
Data InteractionData `json:"data,omitempty"`
|
|
||||||
ChannelID ChannelID `json:"channel_id,omitempty"`
|
ChannelID ChannelID `json:"channel_id,omitempty"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
Version int `json:"version"`
|
Version int `json:"version"`
|
||||||
|
@ -20,119 +23,286 @@ type Interaction struct {
|
||||||
// Only present for component interactions, not command interactions.
|
// Only present for component interactions, not command interactions.
|
||||||
Message *Message `json:"message,omitempty"`
|
Message *Message `json:"message,omitempty"`
|
||||||
|
|
||||||
// Member is only present if this came from a guild.
|
// Member is only present if this came from a guild. To get a user, use the
|
||||||
|
// Sender method.
|
||||||
Member *Member `json:"member,omitempty"`
|
Member *Member `json:"member,omitempty"`
|
||||||
GuildID GuildID `json:"guild_id,omitempty"`
|
GuildID GuildID `json:"guild_id,omitempty"`
|
||||||
|
|
||||||
// User is only present if this didn't come from a guild.
|
// User is only present if this didn't come from a guild. To get a user, use
|
||||||
|
// the Sender method.
|
||||||
User *User `json:"user,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Interaction) UnmarshalJSON(p []byte) error {
|
// Sender returns the sender of this event from either the Member field or the
|
||||||
type interaction Interaction
|
// User field. If neither of those fields are available, then nil is returned.
|
||||||
v := struct {
|
func (e *InteractionEvent) Sender() *User {
|
||||||
Data json.Raw `json:"data,omitempty"`
|
if e.User != nil {
|
||||||
*interaction
|
return e.User
|
||||||
}{interaction: (*interaction)(i)}
|
}
|
||||||
if err := json.Unmarshal(p, &v); err != nil {
|
if e.Member != nil {
|
||||||
|
return &e.Member.User
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenderID returns the sender's ID. See Sender for more information. If Sender
|
||||||
|
// returns nil, then 0 is returned.
|
||||||
|
func (e *InteractionEvent) SenderID() UserID {
|
||||||
|
if sender := e.Sender(); sender != nil {
|
||||||
|
return sender.ID
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InteractionEvent) UnmarshalJSON(b []byte) error {
|
||||||
|
type event InteractionEvent
|
||||||
|
|
||||||
|
target := struct {
|
||||||
|
Type InteractionDataType `json:"type"`
|
||||||
|
Data json.Raw `json:"data"`
|
||||||
|
*event
|
||||||
|
}{
|
||||||
|
event: (*event)(e),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &target); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch v.Type {
|
var err error
|
||||||
case PingInteraction:
|
|
||||||
|
switch target.Type {
|
||||||
|
case PingInteractionType:
|
||||||
|
e.Data = &PingInteraction{}
|
||||||
|
case CommandInteractionType:
|
||||||
|
e.Data = &CommandInteraction{}
|
||||||
|
case ComponentInteractionType:
|
||||||
|
d, err := ParseComponentInteraction(target.Data)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to unmarshal component interaction event data")
|
||||||
|
}
|
||||||
|
e.Data = d
|
||||||
return nil
|
return nil
|
||||||
case ComponentInteraction:
|
|
||||||
i.Data = &ComponentInteractionData{}
|
|
||||||
case CommandInteraction:
|
|
||||||
i.Data = &CommandInteractionData{}
|
|
||||||
default:
|
default:
|
||||||
i.Data = &UnknownInteractionData{typ: v.Type}
|
e.Data = &UnknownInteractionData{
|
||||||
|
Raw: target.Data,
|
||||||
|
typ: target.Type,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Unmarshal(v.Data, i.Data)
|
if err := json.Unmarshal(target.Data, e.Data); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to unmarshal interaction event data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type InteractionType uint
|
func (e *InteractionEvent) MarshalJSON() ([]byte, error) {
|
||||||
|
type event InteractionEvent
|
||||||
|
|
||||||
|
if e.Data == nil {
|
||||||
|
return nil, errors.New("missing InteractionEvent.Data")
|
||||||
|
}
|
||||||
|
if e.Data.InteractionType() == 0 {
|
||||||
|
return nil, errors.New("unexpected 0 InteractionEvent.Data.Type")
|
||||||
|
}
|
||||||
|
|
||||||
|
v := struct {
|
||||||
|
Type InteractionDataType `json:"type"`
|
||||||
|
*event
|
||||||
|
}{
|
||||||
|
Type: e.Data.InteractionType(),
|
||||||
|
event: (*event)(e),
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InteractionDataType is the type of each Interaction, enumerated in
|
||||||
|
// integers.
|
||||||
|
type InteractionDataType uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PingInteraction InteractionType = iota + 1
|
_ InteractionDataType = iota
|
||||||
CommandInteraction
|
PingInteractionType
|
||||||
ComponentInteraction
|
CommandInteractionType
|
||||||
|
ComponentInteractionType
|
||||||
)
|
)
|
||||||
|
|
||||||
// InteractionData holds the data of an interaction.
|
// InteractionData holds the respose data of an interaction, or more
|
||||||
// Type assertions should be made on InteractionData to access the underlying data.
|
// specifically, the data that Discord sends to us. Type assertions should be
|
||||||
// The underlying types of the InteractionData are pointer types.
|
// made on it to access the underlying data. The underlying types of the
|
||||||
|
// Responses are value types. See the constructors for the possible types.
|
||||||
type InteractionData interface {
|
type InteractionData interface {
|
||||||
Type() InteractionType
|
InteractionType() InteractionDataType
|
||||||
|
data()
|
||||||
}
|
}
|
||||||
|
|
||||||
type ComponentInteractionData struct {
|
// PingInteraction is a ping Interaction response.
|
||||||
CustomID string `json:"custom_id"`
|
type PingInteraction struct{}
|
||||||
ComponentType ComponentType `json:"component_type"`
|
|
||||||
Values []string `json:"values"`
|
// InteractionType implements InteractionData.
|
||||||
|
func (*PingInteraction) InteractionType() InteractionDataType { return PingInteractionType }
|
||||||
|
func (*PingInteraction) data() {}
|
||||||
|
|
||||||
|
// ComponentInteraction is a union component interaction response types. The
|
||||||
|
// types can be whatever the constructors for this type will return. Underlying
|
||||||
|
// types of Response are all value types.
|
||||||
|
type ComponentInteraction interface {
|
||||||
|
InteractionData
|
||||||
|
// ID returns the ID of the component in response.
|
||||||
|
ID() ComponentID
|
||||||
|
// Type returns the type of the component in response.
|
||||||
|
Type() ComponentType
|
||||||
|
resp()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*ComponentInteractionData) Type() InteractionType {
|
// SelectInteraction is a select component's response.
|
||||||
return ComponentInteraction
|
type SelectInteraction struct {
|
||||||
|
CustomID ComponentID `json:"custom_id"`
|
||||||
|
Values []string `json:"values"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandInteractionData struct {
|
// ID implements ComponentInteraction.
|
||||||
ID CommandID `json:"id"`
|
func (s *SelectInteraction) ID() ComponentID { return s.CustomID }
|
||||||
Name string `json:"name"`
|
|
||||||
Options []InteractionOption `json:"options"`
|
// Type implements ComponentInteraction.
|
||||||
|
func (s *SelectInteraction) Type() ComponentType { return SelectComponentType }
|
||||||
|
|
||||||
|
// InteractionType implements InteractionData.
|
||||||
|
func (s *SelectInteraction) InteractionType() InteractionDataType {
|
||||||
|
return ComponentInteractionType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*CommandInteractionData) Type() InteractionType {
|
func (s *SelectInteraction) resp() {}
|
||||||
return CommandInteraction
|
func (s *SelectInteraction) data() {}
|
||||||
|
|
||||||
|
// ButtonInteraction is a button component's response. It is the custom ID of
|
||||||
|
// the button within the component tree.
|
||||||
|
type ButtonInteraction struct {
|
||||||
|
CustomID ComponentID `json:"custom_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnknownInteractionData struct {
|
// ID implements ComponentInteraction.
|
||||||
json.Raw
|
func (b *ButtonInteraction) ID() ComponentID { return b.CustomID }
|
||||||
typ InteractionType
|
|
||||||
|
// Type implements ComponentInteraction.
|
||||||
|
func (b *ButtonInteraction) Type() ComponentType { return ButtonComponentType }
|
||||||
|
|
||||||
|
// InteractionType implements InteractionData.
|
||||||
|
func (b *ButtonInteraction) InteractionType() InteractionDataType {
|
||||||
|
return ComponentInteractionType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UnknownInteractionData) Type() InteractionType {
|
func (b *ButtonInteraction) data() {}
|
||||||
return u.typ
|
func (b *ButtonInteraction) resp() {}
|
||||||
|
|
||||||
|
// ParseComponentInteraction parses the given bytes as a component response.
|
||||||
|
func ParseComponentInteraction(b []byte) (ComponentInteraction, error) {
|
||||||
|
var t struct {
|
||||||
|
Type ComponentType `json:"type"`
|
||||||
|
CustomID ComponentID `json:"custom_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, &t); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to unmarshal component interaction header")
|
||||||
|
}
|
||||||
|
|
||||||
|
var d ComponentInteraction
|
||||||
|
|
||||||
|
switch t.Type {
|
||||||
|
case ButtonComponentType:
|
||||||
|
d = &ButtonInteraction{CustomID: t.CustomID}
|
||||||
|
case SelectComponentType:
|
||||||
|
d = &SelectInteraction{CustomID: t.CustomID}
|
||||||
|
default:
|
||||||
|
d = &UnknownComponent{
|
||||||
|
Raw: append(json.Raw(nil), b...),
|
||||||
|
id: t.CustomID,
|
||||||
|
typ: t.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(b, d); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to unmarshal component interaction data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type InteractionOption struct {
|
// CommandInteraction is a command interaction that Discord sends to us.
|
||||||
Name string `json:"name"`
|
type CommandInteraction struct {
|
||||||
Value json.Raw `json:"value"`
|
ID CommandID `json:"id"`
|
||||||
Options []InteractionOption `json:"options"`
|
Name string `json:"name"`
|
||||||
|
Options []CommandInteractionOption `json:"options"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InteractionType implements InteractionData.
|
||||||
|
func (*CommandInteraction) InteractionType() InteractionDataType {
|
||||||
|
return CommandInteractionType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CommandInteraction) data() {}
|
||||||
|
|
||||||
|
// CommandInteractionOption is an option for a Command interaction response.
|
||||||
|
type CommandInteractionOption struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value json.Raw `json:"value"`
|
||||||
|
Options []CommandInteractionOption `json:"options"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// String will return the value if the option's value is a valid string.
|
// String will return the value if the option's value is a valid string.
|
||||||
// Otherwise, it will return the raw JSON value of the other type.
|
// Otherwise, it will return the raw JSON value of the other type.
|
||||||
func (o InteractionOption) String() string {
|
func (o CommandInteractionOption) String() string {
|
||||||
val := string(o.Value)
|
val := string(o.Value)
|
||||||
|
|
||||||
s, err := strconv.Unquote(val)
|
s, err := strconv.Unquote(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o InteractionOption) Int() (int64, error) {
|
// IntValue reads the option's value as an int.
|
||||||
|
func (o CommandInteractionOption) IntValue() (int64, error) {
|
||||||
var i int64
|
var i int64
|
||||||
err := o.Value.UnmarshalTo(&i)
|
err := o.Value.UnmarshalTo(&i)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o InteractionOption) Bool() (bool, error) {
|
// BoolValue reads the option's value as a bool.
|
||||||
|
func (o CommandInteractionOption) BoolValue() (bool, error) {
|
||||||
var b bool
|
var b bool
|
||||||
err := o.Value.UnmarshalTo(&b)
|
err := o.Value.UnmarshalTo(&b)
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o InteractionOption) Snowflake() (Snowflake, error) {
|
// SnowflakeValue reads the option's value as a snowflake.
|
||||||
|
func (o CommandInteractionOption) SnowflakeValue() (Snowflake, error) {
|
||||||
var id Snowflake
|
var id Snowflake
|
||||||
err := o.Value.UnmarshalTo(&id)
|
err := o.Value.UnmarshalTo(&id)
|
||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o InteractionOption) Float() (float64, error) {
|
// FloatValue reads the option's value as a float64.
|
||||||
|
func (o CommandInteractionOption) FloatValue() (float64, error) {
|
||||||
var f float64
|
var f float64
|
||||||
err := o.Value.UnmarshalTo(&f)
|
err := o.Value.UnmarshalTo(&f)
|
||||||
return f, err
|
return f, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnknownInteractionData describes an Interaction response with an unknown
|
||||||
|
// type.
|
||||||
|
type UnknownInteractionData struct {
|
||||||
|
json.Raw
|
||||||
|
typ InteractionDataType
|
||||||
|
}
|
||||||
|
|
||||||
|
// InteractionType implements InteractionData.
|
||||||
|
func (u *UnknownInteractionData) InteractionType() InteractionDataType {
|
||||||
|
return u.typ
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnknownInteractionData) data() {}
|
||||||
|
|
|
@ -75,7 +75,7 @@ type Message struct {
|
||||||
// Reactions contains any reactions to the message.
|
// Reactions contains any reactions to the message.
|
||||||
Reactions []Reaction `json:"reactions,omitempty"`
|
Reactions []Reaction `json:"reactions,omitempty"`
|
||||||
// Components contains any attached components.
|
// Components contains any attached components.
|
||||||
Components []ComponentWrap `json:"components,omitempty"`
|
Components ContainerComponents `json:"components,omitempty"`
|
||||||
|
|
||||||
// Used for validating a message was sent
|
// Used for validating a message was sent
|
||||||
Nonce string `json:"nonce,omitempty"`
|
Nonce string `json:"nonce,omitempty"`
|
||||||
|
|
|
@ -15,16 +15,31 @@ func DurationSinceEpoch(t time.Time) time.Duration {
|
||||||
return time.Duration(t.UnixNano()) - Epoch
|
return time.Duration(t.UnixNano()) - Epoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:generate go run ../utils/gensnowflake -o snowflake_types.go AppID AttachmentID AuditLogEntryID ChannelID CommandID EmojiID GuildID IntegrationID InteractionID MessageID RoleID StageID StickerID StickerPackID TeamID UserID WebhookID
|
||||||
|
|
||||||
|
// Mention generates the mention syntax for this channel ID.
|
||||||
|
func (s ChannelID) Mention() string { return "<#" + s.String() + ">" }
|
||||||
|
|
||||||
|
// Mention generates the mention syntax for this role ID.
|
||||||
|
func (s RoleID) Mention() string { return "<@&" + s.String() + ">" }
|
||||||
|
|
||||||
|
// Mention generates the mention syntax for this user ID.
|
||||||
|
func (s UserID) Mention() string { return "<@" + s.String() + ">" }
|
||||||
|
|
||||||
|
// Snowflake is the format of Discord's ID type. It is a format that can be
|
||||||
|
// sorted chronologically.
|
||||||
type Snowflake uint64
|
type Snowflake uint64
|
||||||
|
|
||||||
// NullSnowflake gets encoded into a null. This is used for
|
// NullSnowflake gets encoded into a null. This is used for
|
||||||
// optional and nullable snowflake fields.
|
// optional and nullable snowflake fields.
|
||||||
const NullSnowflake = ^Snowflake(0)
|
const NullSnowflake = ^Snowflake(0)
|
||||||
|
|
||||||
|
// NewSnowflake creates a new snowflake from the given time.
|
||||||
func NewSnowflake(t time.Time) Snowflake {
|
func NewSnowflake(t time.Time) Snowflake {
|
||||||
return Snowflake((DurationSinceEpoch(t) / time.Millisecond) << 22)
|
return Snowflake((DurationSinceEpoch(t) / time.Millisecond) << 22)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseSnowflake parses a snowflake.
|
||||||
func ParseSnowflake(sf string) (Snowflake, error) {
|
func ParseSnowflake(sf string) (Snowflake, error) {
|
||||||
if sf == "null" {
|
if sf == "null" {
|
||||||
return NullSnowflake, nil
|
return NullSnowflake, nil
|
||||||
|
@ -93,244 +108,3 @@ func (s Snowflake) PID() uint8 {
|
||||||
func (s Snowflake) Increment() uint16 {
|
func (s Snowflake) Increment() uint16 {
|
||||||
return uint16(s & 0xFFF)
|
return uint16(s & 0xFFF)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppID Snowflake
|
|
||||||
|
|
||||||
const NullAppID = AppID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s AppID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *AppID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s AppID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s AppID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s AppID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s AppID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s AppID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s AppID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s AppID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type TeamID Snowflake
|
|
||||||
|
|
||||||
const NullTeamID = AppID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s TeamID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *TeamID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s TeamID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s TeamID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s TeamID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s TeamID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s TeamID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s TeamID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s TeamID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type AttachmentID Snowflake
|
|
||||||
|
|
||||||
const NullAttachmentID = AttachmentID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s AttachmentID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *AttachmentID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s AttachmentID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s AttachmentID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s AttachmentID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s AttachmentID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s AttachmentID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s AttachmentID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s AttachmentID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type AuditLogEntryID Snowflake
|
|
||||||
|
|
||||||
const NullAuditLogEntryID = AuditLogEntryID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s AuditLogEntryID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *AuditLogEntryID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s AuditLogEntryID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s AuditLogEntryID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s AuditLogEntryID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s AuditLogEntryID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s AuditLogEntryID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s AuditLogEntryID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s AuditLogEntryID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type ChannelID Snowflake
|
|
||||||
|
|
||||||
const NullChannelID = ChannelID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s ChannelID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *ChannelID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s ChannelID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s ChannelID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s ChannelID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s ChannelID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s ChannelID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s ChannelID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s ChannelID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
func (s ChannelID) Mention() string { return "<#" + s.String() + ">" }
|
|
||||||
|
|
||||||
type CommandID Snowflake
|
|
||||||
|
|
||||||
const NullCommandID = CommandID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s CommandID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *CommandID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s CommandID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s CommandID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s CommandID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s CommandID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s CommandID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s CommandID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s CommandID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type EmojiID Snowflake
|
|
||||||
|
|
||||||
const NullEmojiID = EmojiID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s EmojiID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *EmojiID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s EmojiID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s EmojiID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s EmojiID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s EmojiID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s EmojiID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s EmojiID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s EmojiID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type IntegrationID Snowflake
|
|
||||||
|
|
||||||
const NullIntegrationID = IntegrationID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s IntegrationID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *IntegrationID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s IntegrationID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s IntegrationID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s IntegrationID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s IntegrationID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s IntegrationID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s IntegrationID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s IntegrationID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type InteractionID Snowflake
|
|
||||||
|
|
||||||
const NullInteractionID = InteractionID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s InteractionID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *InteractionID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s InteractionID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s InteractionID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s InteractionID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s InteractionID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s InteractionID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s InteractionID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s InteractionID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type GuildID Snowflake
|
|
||||||
|
|
||||||
const NullGuildID = GuildID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s GuildID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *GuildID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s GuildID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s GuildID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s GuildID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s GuildID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s GuildID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s GuildID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s GuildID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type MessageID Snowflake
|
|
||||||
|
|
||||||
const NullMessageID = MessageID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s MessageID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *MessageID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s MessageID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s MessageID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s MessageID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s MessageID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s MessageID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s MessageID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s MessageID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type RoleID Snowflake
|
|
||||||
|
|
||||||
const NullRoleID = RoleID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s RoleID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *RoleID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s RoleID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s RoleID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s RoleID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s RoleID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s RoleID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s RoleID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s RoleID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
func (s RoleID) Mention() string { return "<@&" + s.String() + ">" }
|
|
||||||
|
|
||||||
type StageID Snowflake
|
|
||||||
|
|
||||||
const NullStageID = StageID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s StageID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *StageID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s StageID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s StageID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s StageID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s StageID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s StageID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s StageID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s StageID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type StickerID Snowflake
|
|
||||||
|
|
||||||
const NullStickerID = StickerID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s StickerID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *StickerID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s StickerID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s StickerID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s StickerID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s StickerID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s StickerID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s StickerID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s StickerID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type StickerPackID Snowflake
|
|
||||||
|
|
||||||
const NullStickerPackID = StickerPackID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s StickerPackID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *StickerPackID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s StickerPackID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s StickerPackID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s StickerPackID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s StickerPackID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s StickerPackID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s StickerPackID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s StickerPackID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
||||||
type UserID Snowflake
|
|
||||||
|
|
||||||
const NullUserID = UserID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s UserID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *UserID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s UserID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s UserID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s UserID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s UserID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s UserID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s UserID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s UserID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
func (s UserID) Mention() string { return "<@" + s.String() + ">" }
|
|
||||||
|
|
||||||
type WebhookID Snowflake
|
|
||||||
|
|
||||||
const NullWebhookID = WebhookID(NullSnowflake)
|
|
||||||
|
|
||||||
func (s WebhookID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
|
||||||
func (s *WebhookID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
|
||||||
func (s WebhookID) String() string { return Snowflake(s).String() }
|
|
||||||
func (s WebhookID) IsValid() bool { return Snowflake(s).IsValid() }
|
|
||||||
func (s WebhookID) IsNull() bool { return Snowflake(s).IsNull() }
|
|
||||||
func (s WebhookID) Time() time.Time { return Snowflake(s).Time() }
|
|
||||||
func (s WebhookID) Worker() uint8 { return Snowflake(s).Worker() }
|
|
||||||
func (s WebhookID) PID() uint8 { return Snowflake(s).PID() }
|
|
||||||
func (s WebhookID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
||||||
|
|
|
@ -0,0 +1,396 @@
|
||||||
|
// Code generated by gensnowflake. DO NOT EDIT.
|
||||||
|
|
||||||
|
package discord
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// AppID is the snowflake type for a AppID.
|
||||||
|
type AppID Snowflake
|
||||||
|
|
||||||
|
// NullAppID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullAppID = AppID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s AppID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *AppID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s AppID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s AppID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s AppID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s AppID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s AppID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s AppID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s AppID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// AttachmentID is the snowflake type for a AttachmentID.
|
||||||
|
type AttachmentID Snowflake
|
||||||
|
|
||||||
|
// NullAttachmentID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullAttachmentID = AttachmentID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s AttachmentID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *AttachmentID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s AttachmentID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s AttachmentID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s AttachmentID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s AttachmentID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s AttachmentID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s AttachmentID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s AttachmentID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// AuditLogEntryID is the snowflake type for a AuditLogEntryID.
|
||||||
|
type AuditLogEntryID Snowflake
|
||||||
|
|
||||||
|
// NullAuditLogEntryID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullAuditLogEntryID = AuditLogEntryID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s AuditLogEntryID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *AuditLogEntryID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s AuditLogEntryID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s AuditLogEntryID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s AuditLogEntryID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s AuditLogEntryID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s AuditLogEntryID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s AuditLogEntryID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s AuditLogEntryID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// ChannelID is the snowflake type for a ChannelID.
|
||||||
|
type ChannelID Snowflake
|
||||||
|
|
||||||
|
// NullChannelID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullChannelID = ChannelID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s ChannelID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *ChannelID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s ChannelID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s ChannelID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s ChannelID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s ChannelID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s ChannelID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s ChannelID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s ChannelID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// CommandID is the snowflake type for a CommandID.
|
||||||
|
type CommandID Snowflake
|
||||||
|
|
||||||
|
// NullCommandID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullCommandID = CommandID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s CommandID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *CommandID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s CommandID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s CommandID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s CommandID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s CommandID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s CommandID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s CommandID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s CommandID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// EmojiID is the snowflake type for a EmojiID.
|
||||||
|
type EmojiID Snowflake
|
||||||
|
|
||||||
|
// NullEmojiID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullEmojiID = EmojiID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s EmojiID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *EmojiID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s EmojiID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s EmojiID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s EmojiID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s EmojiID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s EmojiID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s EmojiID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s EmojiID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// GuildID is the snowflake type for a GuildID.
|
||||||
|
type GuildID Snowflake
|
||||||
|
|
||||||
|
// NullGuildID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullGuildID = GuildID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s GuildID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *GuildID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s GuildID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s GuildID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s GuildID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s GuildID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s GuildID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s GuildID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s GuildID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// IntegrationID is the snowflake type for a IntegrationID.
|
||||||
|
type IntegrationID Snowflake
|
||||||
|
|
||||||
|
// NullIntegrationID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullIntegrationID = IntegrationID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s IntegrationID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *IntegrationID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s IntegrationID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s IntegrationID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s IntegrationID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s IntegrationID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s IntegrationID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s IntegrationID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s IntegrationID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// InteractionID is the snowflake type for a InteractionID.
|
||||||
|
type InteractionID Snowflake
|
||||||
|
|
||||||
|
// NullInteractionID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullInteractionID = InteractionID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s InteractionID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *InteractionID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s InteractionID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s InteractionID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s InteractionID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s InteractionID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s InteractionID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s InteractionID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s InteractionID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// MessageID is the snowflake type for a MessageID.
|
||||||
|
type MessageID Snowflake
|
||||||
|
|
||||||
|
// NullMessageID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullMessageID = MessageID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s MessageID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *MessageID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s MessageID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s MessageID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s MessageID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s MessageID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s MessageID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s MessageID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s MessageID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// RoleID is the snowflake type for a RoleID.
|
||||||
|
type RoleID Snowflake
|
||||||
|
|
||||||
|
// NullRoleID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullRoleID = RoleID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s RoleID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *RoleID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s RoleID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s RoleID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s RoleID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s RoleID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s RoleID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s RoleID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s RoleID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// StageID is the snowflake type for a StageID.
|
||||||
|
type StageID Snowflake
|
||||||
|
|
||||||
|
// NullStageID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullStageID = StageID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s StageID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *StageID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s StageID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s StageID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s StageID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s StageID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s StageID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s StageID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s StageID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// StickerID is the snowflake type for a StickerID.
|
||||||
|
type StickerID Snowflake
|
||||||
|
|
||||||
|
// NullStickerID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullStickerID = StickerID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s StickerID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *StickerID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s StickerID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s StickerID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s StickerID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s StickerID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s StickerID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s StickerID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s StickerID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// StickerPackID is the snowflake type for a StickerPackID.
|
||||||
|
type StickerPackID Snowflake
|
||||||
|
|
||||||
|
// NullStickerPackID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullStickerPackID = StickerPackID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s StickerPackID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *StickerPackID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s StickerPackID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s StickerPackID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s StickerPackID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s StickerPackID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s StickerPackID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s StickerPackID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s StickerPackID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// TeamID is the snowflake type for a TeamID.
|
||||||
|
type TeamID Snowflake
|
||||||
|
|
||||||
|
// NullTeamID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullTeamID = TeamID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s TeamID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *TeamID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s TeamID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s TeamID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s TeamID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s TeamID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s TeamID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s TeamID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s TeamID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// UserID is the snowflake type for a UserID.
|
||||||
|
type UserID Snowflake
|
||||||
|
|
||||||
|
// NullUserID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullUserID = UserID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s UserID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *UserID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s UserID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s UserID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s UserID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s UserID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s UserID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s UserID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s UserID) Increment() uint16 { return Snowflake(s).Increment() }
|
||||||
|
|
||||||
|
// WebhookID is the snowflake type for a WebhookID.
|
||||||
|
type WebhookID Snowflake
|
||||||
|
|
||||||
|
// NullWebhookID gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const NullWebhookID = WebhookID(NullSnowflake)
|
||||||
|
|
||||||
|
func (s WebhookID) MarshalJSON() ([]byte, error) { return Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *WebhookID) UnmarshalJSON(v []byte) error { return (*Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s WebhookID) String() string { return Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s WebhookID) IsValid() bool { return Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s WebhookID) IsNull() bool { return Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s WebhookID) Time() time.Time { return Snowflake(s).Time() }
|
||||||
|
func (s WebhookID) Worker() uint8 { return Snowflake(s).Worker() }
|
||||||
|
func (s WebhookID) PID() uint8 { return Snowflake(s).PID() }
|
||||||
|
func (s WebhookID) Increment() uint16 { return Snowflake(s).Increment() }
|
|
@ -397,7 +397,7 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
type InteractionCreateEvent struct {
|
type InteractionCreateEvent struct {
|
||||||
discord.Interaction
|
discord.InteractionEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undocumented
|
// Undocumented
|
||||||
|
|
|
@ -193,6 +193,7 @@ func NewCustomIdentifiedGateway(gatewayURL string, id *Identifier) *Gateway {
|
||||||
|
|
||||||
ErrorLog: wsutil.WSError,
|
ErrorLog: wsutil.WSError,
|
||||||
AfterClose: func(error) {},
|
AfterClose: func(error) {},
|
||||||
|
PacerLoop: wsutil.PacemakerLoop{ErrorLog: wsutil.WSError},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
||||||
module github.com/diamondburned/arikawa/v3
|
module github.com/diamondburned/arikawa/v3
|
||||||
|
|
||||||
go 1.13
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/schema v1.2.0
|
github.com/gorilla/schema v1.2.0
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"go/format"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type data struct {
|
||||||
|
Package string
|
||||||
|
ImportDiscord bool
|
||||||
|
Snowflakes []snowflakeType
|
||||||
|
}
|
||||||
|
|
||||||
|
type snowflakeType struct {
|
||||||
|
TypeName string
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:embed template.tmpl
|
||||||
|
var packageTmpl string
|
||||||
|
|
||||||
|
var tmpl = template.Must(template.New("").Parse(packageTmpl))
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var pkg string
|
||||||
|
var out string
|
||||||
|
|
||||||
|
log.SetFlags(0)
|
||||||
|
|
||||||
|
flag.Usage = func() {
|
||||||
|
log.Printf("usage: %s [-p package] <type names...>", filepath.Base(os.Args[0]))
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.StringVar(&out, "o", "", "output, empty for stdout")
|
||||||
|
flag.StringVar(&pkg, "p", "discord", "package name")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(flag.Args()) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
d := data{
|
||||||
|
Package: pkg,
|
||||||
|
ImportDiscord: pkg != "discord",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range flag.Args() {
|
||||||
|
d.Snowflakes = append(d.Snowflakes, snowflakeType{
|
||||||
|
TypeName: arg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := tmpl.Execute(&buf, d); err != nil {
|
||||||
|
log.Fatalln("failed to execute template:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("failed to fmt:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile := os.Stdout
|
||||||
|
|
||||||
|
if out != "" {
|
||||||
|
f, err := os.Create(out)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("failed to create output file:", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
outFile = f
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := outFile.Write(b); err != nil {
|
||||||
|
log.Fatalln("failed to write to file:", err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Code generated by gensnowflake. DO NOT EDIT.
|
||||||
|
|
||||||
|
package {{ .Package }}
|
||||||
|
|
||||||
|
{{ $dot := "" }}
|
||||||
|
|
||||||
|
{{ if .ImportDiscord }}
|
||||||
|
{{ $dot = "discord." }}
|
||||||
|
import "github.com/diamondburned/arikawa/v3/discord"
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
{{ range .Snowflakes }}
|
||||||
|
|
||||||
|
// {{ .TypeName }} is the snowflake type for a {{ .TypeName }}.
|
||||||
|
type {{.TypeName}} {{$dot}}Snowflake
|
||||||
|
|
||||||
|
// Null{{.TypeName}} gets encoded into a null. This is used for optional and nullable snowflake fields.
|
||||||
|
const Null{{.TypeName}} = {{.TypeName}}({{$dot}}NullSnowflake)
|
||||||
|
|
||||||
|
func (s {{.TypeName}}) MarshalJSON() ([]byte, error) { return {{$dot}}Snowflake(s).MarshalJSON() }
|
||||||
|
func (s *{{.TypeName}}) UnmarshalJSON(v []byte) error { return (*{{$dot}}Snowflake)(s).UnmarshalJSON(v) }
|
||||||
|
|
||||||
|
// String returns the ID, or nothing if the snowflake isn't valid.
|
||||||
|
func (s {{.TypeName}}) String() string { return {{$dot}}Snowflake(s).String() }
|
||||||
|
|
||||||
|
// IsValid returns whether or not the snowflake is valid.
|
||||||
|
func (s {{.TypeName}}) IsValid() bool { return {{$dot}}Snowflake(s).IsValid() }
|
||||||
|
|
||||||
|
// IsNull returns whether or not the snowflake is null.
|
||||||
|
func (s {{.TypeName}}) IsNull() bool { return {{$dot}}Snowflake(s).IsNull() }
|
||||||
|
|
||||||
|
func (s {{.TypeName}}) Time() time.Time { return {{$dot}}Snowflake(s).Time() }
|
||||||
|
func (s {{.TypeName}}) Worker() uint8 { return {{$dot}}Snowflake(s).Worker() }
|
||||||
|
func (s {{.TypeName}}) PID() uint8 { return {{$dot}}Snowflake(s).PID() }
|
||||||
|
func (s {{.TypeName}}) Increment() uint16 { return {{$dot}}Snowflake(s).Increment() }
|
||||||
|
{{ end }}
|
|
@ -267,7 +267,7 @@ func (c *Client) request(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optionally unmarshal the error.
|
// Optionally unmarshal the error.
|
||||||
json.Unmarshal(httpErr.Body, &httpErr)
|
json.Unmarshal(httpErr.Body, httpErr)
|
||||||
|
|
||||||
doErr = httpErr
|
doErr = httpErr
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue