Code Monkey home page Code Monkey logo

ken's Introduction

ken   GitHub tag (latest by date) Go Report Card

Warning
This package is still in an early state of development and future updates might introduce breaking changes to the API until the first official release.

(ken - japanese for Sword) - A cutting edge (haha), object-oriented and highly modular Discord application commands and interaction handler for Discordgo.

For basic usage examples, see the basic example section. Examples on how to use middlewares can be found here.

This package was primarily written with the motivation to use it in my Discord bot shinpuru. So some design decision might be influenced by that.

All you need to know

Why should you use this package?

ken tries to provide an "everything in the kitchen skink" framework to simplify and speed up bot development using the Discord interaction API. It also tries to provide a great developer experience while giving you full control over the underlying event data and API interactions – just in the style of discordgo itself.

Also, ken provides a higly modular middleware pipeline to control who can use commands and how they should be handled.

Things you can do with ken:

High modularity

The command-registration and middleware system is built so that you can add whatever functionality you want to your command structure and handle it all in your middleware which can be called before and/or after command execution. The only thing required is that your commands implements one of the provided command interfaes:

Command Pipeline

In the middleware example, you can take a look at how to implement custom functionality in your command structure and add middleware functions to handle these.

Via options you can also specify a custom state handler, if you are using something like dgrs for example.

Quality of Life Implementations

ken passes a single Context object to the command handlers which contains everything you need. It allows you to access raw discordgo.InteractionCreate event data, the Command instance which has been called, the discordgo.Session, as well as many utility functions.

For example, you can easily respond to the event by using the Respond method to send a response to an interaction. Defer does the same but sends a defer response so you can send follow-up messages afterwards with a delay.

Speaking of follow-up messages, there are some simple functions like FollowUp, FollowUpEmbed or FollowUpError to make building these follow-up messages easier. These functions return a single FollowUpMessage object so that you can chain calls like DeleteAfter to delete the follow-up message after a given timespan. 🤯

The Ctx also allows you to handle sub-commands using HandleSubCommands. Simply pass a name and handler function as SubCommandHandler to build your sub-command tree. The sub-command handlers are passed a specialized SubCommandCtx, which scopes the Options method to the options of the sub-command. So you can handle options like you would in a top-level command. In this example you can see a practical implementation of sub-commands.

Performance

To avoid registering and unregistering commands everytime the bot restarts, ken allows to cache commands using a CommandStore. Although disabled by default, the provided default implementation LocalCommandStore can be used. It stores the commands in a file which will be tried to read from on the next startup. You can also implement your own store, with Redis for example.

ken uses sync.Pool as object pools for the command context which are used for command and sub-command execution. This is done to avoid creating a new context object for each command execution which would put strain on the garbage collector, especially on high command execution frequencies.

Example Usage

package main

// imports ...

type TestCommand struct{}

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

func (c *TestCommand) Name() string {
	return "ping"
}

func (c *TestCommand) Description() string {
	return "Basic Ping Command"
}

func (c *TestCommand) Version() string {
	return "1.0.0"
}

func (c *TestCommand) Options() []*discordgo.ApplicationCommandOption {
	return []*discordgo.ApplicationCommandOption{}
}

func (c *TestCommand) Run(ctx ken.Context) (err error) {
	err = ctx.Respond(&discordgo.InteractionResponse{
		Type: discordgo.InteractionResponseChannelMessageWithSource,
		Data: &discordgo.InteractionResponseData{
			Content: "Pong!",
		},
	})
	return
}

func main() {
	token := os.Getenv("TOKEN")

	session, err := discordgo.New("Bot " + token)
	if err != nil {
		panic(err)
	}
	defer session.Close()

	k := ken.New(session)
	k.RegisterCommands(
		new(commands.TestCommand),
	)

	defer k.Unregister()

	err = session.Open()
	if err != nil {
		panic(err)
	}

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc
}

You can also find a "real world" implementation in my Discord Bot shinpuru, where ken is used as main slash command framework.

FAQ

Why do my commands not show up in Discord?

This may have multiple reasons.

  1. Check if you invited your Bot with the applications.commands OAuth2 scope. This option was added for bots to be permitted to create slash commands for a guild. When you already invited your bot before that, the bot will not be able to register slash commands. To fix this, simply kick the bot and re-invite it with an invite link containing the required applications.commands scope.

    Pro-Tip: You can go to the OAuth2 Page in the Discord Application settings to generate a suitable invite link.

  2. When a command needs to be created (if you start the bot with a newly added command), It may take up to 15-30 minutes (based on personal experience) until the command shows up in Guilds. After that (when CommandStore is enabled), commands are re-used and updated, which does not take that much time.

    Pro-Tip: To create a command, you just need to specify a valid name, description and options and add it to ken's handler register. After that, start the bot in the background and then implement the command logic to bridge the time until the command shows up to test it.

  3. As I have experienced personally, sometimes, you might need to restart your Discord client until commands show op on Guilds. And sometimes you even need to kick and re-invite the bot so that they show up. I don't really know if this is a registration issue on ken's site. If you know more about that, please let me know!

Why do I get the error command name is invalid?

Discord has some very strong restrictions to the naming of commands and command options. The name of a command, sub command or command option must be unique and must match the regex ^[a-z0-9-_]{1,32}$¹.

If you are not familiar with regex, the name must match the following conditions:

  • It must only contain lowercase letters, numbers, dashes and underscores.
  • It must be at least 1 character and at most 32 characters long.

¹ The pattern described in the Discord docs ^[\w-]{1,32}$ is actually not accurate, because you can not use uppercase letters in names, but you can use underscores.

Projects using ken

If you used ken in your project, feel free to add it here with a pull request. 😉


© 2022 Ringo Hoffmann (zekro Development).
Covered by the MIT Licence.

ken's People

Contributors

n0c1337 avatar pujux avatar scderox avatar sema0205 avatar snowjuli avatar zekrotja avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ken's Issues

Add message components on message creation

Currently, message components are added after the message has been sent by editing the message. Unfortunately, this does not work with ephemeral messages, so it should be possible to send a follow-up message with message components already attached on sending the message.

This issue is related to zekroTJA/shinpuru#394.

Updating Application Commands instead of deleting/creating them

Because only 200 commands can be created at one day, it would be better for development if commands registered could be temporarily saved and then updated instead of deleted and re-created.

This would require some kind of temporary command store to save to and read commands from.

Provide endpoint to get all registered commands with their details

There should be an endpoint on Ken like GetCommandInfo() which returns a list of all registered commands with their details.

It should also be possible to pass custom info parsers to ensure availability of additional fields added via custom command implementations.

Use ken with discordgo.InteractionCreate

Hi, I'm starting to use Ken on a new project. But when I register a listener to discordgo.InteractionCreate events I got panic: MessageComponentData called on interaction of type ApplicationCommand. There is any way to continue using ken and also listen to InteractionCreate?

Support for user apps

Short description

Hello,

Recently, discord rolled out a new feature allowing bots to be linked to a user and used in DM's upon other things. Discordgo currently has an open pull request to adapt this feature, but I assume it will be merged soon. It would be very nice to have ken also able to support these commands in direct messages.

Attachments

No response

FollowUp Messages sometimes lead to `interaction failed` error

Sending Ctx#FollowUp after Ctx#Defer sometimes lead to an interaction failed error.

image

This might be cause by waiting for server response.

ken/context.go

Lines 71 to 75 in 281f024

return c.FollowUp(true, &discordgo.WebhookParams{
Embeds: []*discordgo.MessageEmbed{
emb,
},
})

It might also be a timing issue that the follow up arrives at the server earlier than the defer. This might be tested further.

Message Component Bindings

  • Add message component bindings to command interaction responses and follow up messages.
  • Add event handlers for message component interactions.

add new guild scope to slash commands

add new guild scope to slash commands

As we discussed, this project needs an implementation for guild scoped slash commands, especially for faster testing commands.

As the documentation says.

Global commands are cached for 1 hour. That means that new global commands will fan out slowly across all guilds, and will be guaranteed to be updated in an hour.
read more

and

Guild commands update instantly. We recommend you use guild commands for quick testing, and global commands when they're ready for public use.
read more

as it seems, they differ only by the URL

url = "https://discord.com/api/v8/applications/<my_application_id>/commands"
url = "https://discord.com/api/v8/applications/<my_application_id>/guilds/<guild_id>/commands"

and in the official discord-go library it's also just a small change

// ApplicationCommandCreate creates a global application command and returns it.
// appID       : The application ID.
// guildID     : Guild ID to create guild-specific application command. If empty - creates global application command.
// cmd         : New application command data.
func (s *Session) ApplicationCommandCreate(appID string, guildID string, cmd *ApplicationCommand) (ccmd *ApplicationCommand, err error) {

read more

so as I see, we need only replace the default value right here, to a guild-id to register commands in a smaller scope

ccmd, err = s.ApplicationCommandCreate(e.User.ID, "", toApplicationCommand(cmd))

read more

Things we need to observe

  • backward compatibility to older ken versions, so we should keep the old names RegisterCommands and registerCommand and rename the new version to something like RegisterCommandsByGuildID and registerCommandByGuildID

Delete RespondEmbed?

Hello,

With a RespondEmbed I don’t see that DeleteAfter is available nor do I see a way to delete it in general. Is it still possible to delete it somehow?

Thank you

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.