Creating Your First Command
A command is nothing more than a type implementing the plugin.Command interface. That interface is defined as follows:
type Command interface {
CommandMeta
Invoke(*state.State, *Context) (interface{}, error)
}CommandMeta is another interface consisting of getters for the command's metadata. You don't really need to worry about the methods it requires, as the command package provides us with predefined types.
Creating a Command
Using that knowledge, you can create your first command. Create a package with your commands name, as detailed in Project Layout, and add a {{package_name}}.go file to it.
Example: A Ping Command
In the ping package create a ping.go file where you create your command type. To implement the plugin.CommandMeta interface, which is part of the plugin.Command interface, you can embed command.Meta in your Ping type.
package ping
import (
"github.com/mavolin/adam/pkg/impl/command"
"github.com/mavolin/adam/pkg/plugin"
)
type Ping struct {
command.Meta
}
var _ plugin.Command = new(Ping) // compile time checkThis leaves your Ping command with only Invoke left, to fully satisfy plugin.Command.
import (
...
"github.com/diamondburned/ariakwa/v2/state"
"github.com/mavolin/adam/plg/plugin"
"time"
)
...
func (p *Ping) Invoke(_ *state.State, ctx *plugin.Context) (interface{}, error) {
t := time.Now()
msg, err := ctx.Reply("The ping to discord is `calculating...`")
if err != nil {
return nil, err
}
_, err := ctx.Editf(msg.ID, "The ping to discord is %d ms",
time.Since(now).Milliseconds())
return nil, err
}Now that we've added Invoke, let's add a constructor function where we create a new Ping instance and fill the command.Meta struct we embedded earlier.
import (
...
"github.com/diamondburned/arikawa/v2/discord"
"github.com/mavolin/adam/pkg/plugin"
"github.com/mavolin/adam/pkg/impl/command"
)
var _ plugin.Command = new(Ping) // compile-time check
// New creates a new Ping command.
func New() *Ping {
return &Ping{
Meta: command.Meta{
Name: "ping",
ShortDescription: "Tells you the ping to Discord's servers.",
ChannelTypes: plugin.AllChannels,
BotPermissions: discord.SendMessagesPermission,
},
}
}
func (p *Ping) Invoke(_ *state.State, ctx *plugin.Context) (interface{}, error) {
...
}Invoke's Return Values
As you might have noticed, plugin.Command.Invoke has two return values, and while the error return value might be a bit more self-explanatory, interface{} is probably not. So what can you use it for?
Everything you return as the first value will get turned into a message and sent in the invoking channel back to the user using the plugin.Context's Replier. Obviously, not everything can be turned into a message, at least not without causing confusion. Therefore, only the following return types are allowed:
uint,uint8,uint16,uint32,uint64int,int8,int16,int32,int64float32,float64stringdiscord.Embedand*discord.Embed*embedutil.Builderapi.SendMessageDatai18n.Term*i18n.Configany type implementing
plugin.Reply
Of course, justnil is also valid, and won't create any response.
The second return value, error, is handed to the bot's error handler if it's not nil. While you can define a custom error handler, the default one will wrap every error not implementing errors.Error into a errors.InternalError and call Handle on it. We'll take a closer look at this later on in the Error Types chapter.
Last updated
Was this helpful?