Skip to content

v0.11.1

Compare
Choose a tag to compare
@zekroTJA zekroTJA released this 20 Nov 14:04
· 67 commits to master since this release

⚠️ Attention: This version introduces breaking changes!
If you are using these interface type checks shown below, you might need to replace ken.Command with ken.SlashCommand for appropriate type checking.

var _ ken.SlashCommand = (*TestCommand)(nil)

This version allows to also handle user and message commands using the same middleware pipeline as used for slash commands. Therefore, 3 new interfaces have been introduced to define slash, user and message commands.

slashcommand.go

// SlashCommand defines a callable slash command.
type SlashCommand interface {
	Command

	// Version returns the commands semantic version.
	Version() string

	// Options returns an array of application
	// command options.
	Options() []*discordgo.ApplicationCommandOption
}

usercommand.go

// UserCommand defines a callable user command.
type UserCommand interface {
	Command

	// TypeUser is used to differenciate between
	// UserCommand and MessageCommand which have
	// the same structure otherwise.
	//
	// This method must only be implemented and
	// will never be called by ken, so it can be
	// completely empty.
	TypeUser()
}

messagecommand.go

// MessageCommand defines a callable message command.
type MessageCommand interface {
	Command

	// TypeMessage is used to differenciate between
	// UserCommand and MessageCommand which have
	// the same structure otherwise.
	//
	// This method must only be implemented and
	// will never be called by ken, so it can be
	// completely empty.
	TypeMessage()
}

As you can see, all three of them extend the Command interface.

command.go

type Command interface {
	// Name returns the unique name of the command.
	Name() string

	// Description returns a brief text which concisely
	// describes the commands purpose.
	Description() string

	// Run is called on command invokation getting
	// passed the invocation context.
	//
	// When something goes wrong during command
	// execution, you can return an error which is
	// then handled by Ken's OnCommandError handler.
	Run(ctx *Ctx) (err error)
}

func toApplicationCommand(c Command) *discordgo.ApplicationCommand {
	switch cm := c.(type) {
	case UserCommand:
		return &discordgo.ApplicationCommand{
			Name: cm.Name(),
			Type: discordgo.UserApplicationCommand,
		}
	case MessageCommand:
		return &discordgo.ApplicationCommand{
			Name: cm.Name(),
			Type: discordgo.MessageApplicationCommand,
		}
	case SlashCommand:
		return &discordgo.ApplicationCommand{
			Name:        cm.Name(),
			Type:        discordgo.ChatApplicationCommand,
			Description: cm.Description(),
			Version:     cm.Version(),
			Options:     cm.Options(),
		}
	default:
		panic(fmt.Sprintf("Command type not implemented for command: %s", cm.Name()))
	}
}

This allows to register user and message commands using the same Ken#RegisterCommand endpoint as before.

To differentiate between user and message commands - because they effectively have the same API structure - there are the two shallow methods TypeUser() and TypeMessage(). These have absolutely no programmatically purpose and are only there for type differentiation. I know, this is kinda janky but otherwise this approach would hardly be possible this way at the moment.

This also allows the re-usage of existing code from slash commands in user commands. To view a "real world" example, please take a look at the implementation of the user slash command and userinfo user command implementation in shinpuru.