Improve handling of invalid interaction situations

This commit is contained in:
Carson Hoffman 2021-07-25 13:39:31 -04:00
parent 421e149650
commit 083bf5c1d9
No known key found for this signature in database
GPG key ID: 05B660CB452C657F

View file

@ -5,6 +5,7 @@ import (
"crypto/ed25519" "crypto/ed25519"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -40,6 +41,30 @@ const (
ApplicationCommandOptionMentionable ApplicationCommandOptionType = 9 ApplicationCommandOptionMentionable ApplicationCommandOptionType = 9
) )
func (t ApplicationCommandOptionType) String() string {
switch t {
case ApplicationCommandOptionSubCommand:
return "SubCommand"
case ApplicationCommandOptionSubCommandGroup:
return "SubCommandGroup"
case ApplicationCommandOptionString:
return "String"
case ApplicationCommandOptionInteger:
return "Integer"
case ApplicationCommandOptionBoolean:
return "Boolean"
case ApplicationCommandOptionUser:
return "User"
case ApplicationCommandOptionChannel:
return "Channel"
case ApplicationCommandOptionRole:
return "Role"
case ApplicationCommandOptionMentionable:
return "Mentionable"
}
return fmt.Sprintf("ApplicationCommandOptionType(%d)", t)
}
// ApplicationCommandOption represents an option/subcommand/subcommands group. // ApplicationCommandOption represents an option/subcommand/subcommands group.
type ApplicationCommandOption struct { type ApplicationCommandOption struct {
Type ApplicationCommandOptionType `json:"type"` Type ApplicationCommandOptionType `json:"type"`
@ -69,6 +94,18 @@ const (
InteractionMessageComponent InteractionType = 3 InteractionMessageComponent InteractionType = 3
) )
func (t InteractionType) String() string {
switch t {
case InteractionPing:
return "Ping"
case InteractionApplicationCommand:
return "ApplicationCommand"
case InteractionMessageComponent:
return "MessageComponent"
}
return fmt.Sprintf("InteractionType(%d)", t)
}
// Interaction represents data of an interaction. // Interaction represents data of an interaction.
type Interaction struct { type Interaction struct {
ID string `json:"id"` ID string `json:"id"`
@ -135,12 +172,18 @@ func (i *Interaction) UnmarshalJSON(raw []byte) error {
// MessageComponentData is helper function to assert the inner InteractionData to MessageComponentInteractionData. // MessageComponentData is helper function to assert the inner InteractionData to MessageComponentInteractionData.
// Make sure to check that the Type of the interaction is InteractionMessageComponent before calling. // Make sure to check that the Type of the interaction is InteractionMessageComponent before calling.
func (i Interaction) MessageComponentData() (data MessageComponentInteractionData) { func (i Interaction) MessageComponentData() (data MessageComponentInteractionData) {
if i.Type != InteractionMessageComponent {
panic("MessageComponentData called on interaction of type " + i.Type.String())
}
return i.Data.(MessageComponentInteractionData) return i.Data.(MessageComponentInteractionData)
} }
// ApplicationCommandData is helper function to assert the inner InteractionData to ApplicationCommandInteractionData. // ApplicationCommandData is helper function to assert the inner InteractionData to ApplicationCommandInteractionData.
// Make sure to check that the Type of the interaction is InteractionApplicationCommand before calling. // Make sure to check that the Type of the interaction is InteractionApplicationCommand before calling.
func (i Interaction) ApplicationCommandData() (data ApplicationCommandInteractionData) { func (i Interaction) ApplicationCommandData() (data ApplicationCommandInteractionData) {
if i.Type != InteractionApplicationCommand {
panic("ApplicationCommandData called on interaction of type " + i.Type.String())
}
return i.Data.(ApplicationCommandInteractionData) return i.Data.(ApplicationCommandInteractionData)
} }
@ -186,31 +229,31 @@ func (MessageComponentInteractionData) Type() InteractionType {
// ApplicationCommandInteractionDataOption represents an option of a slash command. // ApplicationCommandInteractionDataOption represents an option of a slash command.
type ApplicationCommandInteractionDataOption struct { type ApplicationCommandInteractionDataOption struct {
Name string `json:"name"` Name string `json:"name"`
// NOTE: Contains the value specified by InteractionType. Type ApplicationCommandOptionType `json:"type"`
// NOTE: Contains the value specified by Type.
Value interface{} `json:"value,omitempty"` Value interface{} `json:"value,omitempty"`
Options []*ApplicationCommandInteractionDataOption `json:"options,omitempty"` Options []*ApplicationCommandInteractionDataOption `json:"options,omitempty"`
} }
// IntValue is a utility function for casting option value to integer // IntValue is a utility function for casting option value to integer
func (o ApplicationCommandInteractionDataOption) IntValue() int64 { func (o ApplicationCommandInteractionDataOption) IntValue() int64 {
if v, ok := o.Value.(float64); ok { if o.Type != ApplicationCommandOptionInteger {
return int64(v) panic("IntValue called on data option of type " + o.Type.String())
} }
return int64(o.Value.(float64))
return 0
} }
// UintValue is a utility function for casting option value to unsigned integer // UintValue is a utility function for casting option value to unsigned integer
func (o ApplicationCommandInteractionDataOption) UintValue() uint64 { func (o ApplicationCommandInteractionDataOption) UintValue() uint64 {
if v, ok := o.Value.(float64); ok { if o.Type != ApplicationCommandOptionInteger {
return uint64(v) panic("UintValue called on data option of type " + o.Type.String())
} }
return uint64(o.Value.(float64))
return 0
} }
// FloatValue is a utility function for casting option value to float // FloatValue is a utility function for casting option value to float
func (o ApplicationCommandInteractionDataOption) FloatValue() float64 { func (o ApplicationCommandInteractionDataOption) FloatValue() float64 {
// TODO: limit calls to Number type once it is released
if v, ok := o.Value.(float64); ok { if v, ok := o.Value.(float64); ok {
return v return v
} }
@ -220,29 +263,27 @@ func (o ApplicationCommandInteractionDataOption) FloatValue() float64 {
// StringValue is a utility function for casting option value to string // StringValue is a utility function for casting option value to string
func (o ApplicationCommandInteractionDataOption) StringValue() string { func (o ApplicationCommandInteractionDataOption) StringValue() string {
if v, ok := o.Value.(string); ok { if o.Type != ApplicationCommandOptionString {
return v panic("StringValue called on data option of type " + o.Type.String())
} }
return o.Value.(string)
return ""
} }
// BoolValue is a utility function for casting option value to bool // BoolValue is a utility function for casting option value to bool
func (o ApplicationCommandInteractionDataOption) BoolValue() bool { func (o ApplicationCommandInteractionDataOption) BoolValue() bool {
if v, ok := o.Value.(bool); ok { if o.Type != ApplicationCommandOptionBoolean {
return v panic("BoolValue called on data option of type " + o.Type.String())
} }
return o.Value.(bool)
return false
} }
// ChannelValue is a utility function for casting option value to channel object. // ChannelValue is a utility function for casting option value to channel object.
// s : Session object, if not nil, function additionally fetches all channel's data // s : Session object, if not nil, function additionally fetches all channel's data
func (o ApplicationCommandInteractionDataOption) ChannelValue(s *Session) *Channel { func (o ApplicationCommandInteractionDataOption) ChannelValue(s *Session) *Channel {
chanID := o.StringValue() if o.Type != ApplicationCommandOptionChannel {
if chanID == "" { panic("ChannelValue called on data option of type " + o.Type.String())
return nil
} }
chanID := o.Value.(string)
if s == nil { if s == nil {
return &Channel{ID: chanID} return &Channel{ID: chanID}
@ -262,10 +303,10 @@ func (o ApplicationCommandInteractionDataOption) ChannelValue(s *Session) *Chann
// RoleValue is a utility function for casting option value to role object. // RoleValue is a utility function for casting option value to role object.
// s : Session object, if not nil, function additionally fetches all role's data // s : Session object, if not nil, function additionally fetches all role's data
func (o ApplicationCommandInteractionDataOption) RoleValue(s *Session, gID string) *Role { func (o ApplicationCommandInteractionDataOption) RoleValue(s *Session, gID string) *Role {
roleID := o.StringValue() if o.Type != ApplicationCommandOptionRole && o.Type != ApplicationCommandOptionMentionable {
if roleID == "" { panic("RoleValue called on data option of type " + o.Type.String())
return nil
} }
roleID := o.Value.(string)
if s == nil || gID == "" { if s == nil || gID == "" {
return &Role{ID: roleID} return &Role{ID: roleID}
@ -290,10 +331,10 @@ func (o ApplicationCommandInteractionDataOption) RoleValue(s *Session, gID strin
// UserValue is a utility function for casting option value to user object. // UserValue is a utility function for casting option value to user object.
// s : Session object, if not nil, function additionally fetches all user's data // s : Session object, if not nil, function additionally fetches all user's data
func (o ApplicationCommandInteractionDataOption) UserValue(s *Session) *User { func (o ApplicationCommandInteractionDataOption) UserValue(s *Session) *User {
userID := o.StringValue() if o.Type != ApplicationCommandOptionUser && o.Type != ApplicationCommandOptionMentionable {
if userID == "" { panic("UserValue called on data option of type " + o.Type.String())
return nil
} }
userID := o.Value.(string)
if s == nil { if s == nil {
return &User{ID: userID} return &User{ID: userID}