Categorygithub.com/Postcord/router
modulepackage
0.2.0
Repository: https://github.com/postcord/router.git
Documentation: pkg.go.dev

# README

router

A high level Postcord interactions router. This code implements a modified version of the binary tree from httprouter (see tree.go). This is licensed under the BSD license.

How does this work?

This package consists of 2 routers (a components router and a commands router), and a function to bootstrap the routers and set any global configurations which affect them both. Each router has been designed to work well for its specific usecase.

Components Router

Routing components was traditionally quite complicated. You could use a standard map, but then you would lose the ability to track state. You could put the state in the string, but then you would either need to make a cache lookup, or you would need to do complicated and expensive string splitting.

Postcord gets around this by using a fork of the tree that httprouter/fasthttprouter uses for our component routes. This means that we have the ability to track state whilst making the application performant.

To begin with, we will go ahead and define the router somewhere where any of the components that wish to access it can see.

var componentRouter = &router.ComponentRouter{}

Note that we can directly initialise this object. There's no new function. From here, we can go ahead and add functionality to this router.

There are 2 functions we can use to add components:

  • RegisterButton(route string, cb ButtonFunc): The job of this is to allow you to register button components. The signature for ButtonFunc takes *ComponentRouterCtx as the first argument and returns an error. See creating responses with the context to see how you would make a response with the context handed down for this button.
  • RegisterSelectMenu(route string, cb SelectMenuFunc): The job of this is to allow you to register select menu components. The signature for SelectMenuFunc takes *ComponentRouterCtx as the first argument, and []string as the second (this will contian the choices that the user made). It will then return an error. See creating responses with the context to see how you would make a response with the context handed down for this button.

It is important to note that in both instances, we can use parameters in the path. This is awesome for inputting user data, however it is important to validate the data! Do not trust this input as it can be manipulated by users! As with httprouter, this can be done with :paramName in the path. For example, we could go ahead and register the following button:

componentRouter.RegisterButton("/name/:name", func(ctx *router.ComponentRouterCtx) error {
	ctx.SetEmbed(&objects.Embed{Description: "my name " + ctx.Params["name"]})
	return nil
})

From here, we could go ahead and import this path in a component with the custom ID /name/Jeff and when clicked it would reply with an embed saying my name Jeff.

Commands Router

One thing that is even more difficult to route than components is commands. Routing through sub-commands requires a lot of mind bending iteration, but don't worry, we have your back and have created a high level commands router too!

The same as with interactions, you will firstly want to go ahead and make the commands router:

var commandRouter = &router.CommandRouter{}

Now we have a commands router created, we can now add to it.

To register a group, both CommandRouter and CommandGroup (to allow for one sub-group as per Discord's nesting rules) have the NewCommandGroup and MustNewCommandGroup functions. This will allow you to make a command group, which will then allow you to create commands/groups to be nested inside of it.

To register a command, we can go ahead and call NewCommandBuilder on either a router or group with the argument being the name of the command. From here, we can set the following options:

TODO

Options

TODO

Creating Responses with the Context

TODO

Router Loader

So we went ahead and created both our routers. Awesome! But we need to get these into the application somehow. Don't worry, we thought of a very elegant way to do this. The RouterLoader function will create a builder which we can use to go ahead to build and execute the loader. We can use the following options in our chain:

  • ComponentRouter(*ComponentRouter) LoaderBuilder: Adds the component router specified into the loader.
  • CommandRouter(*CommandRouter) LoaderBuilder: Adds the commands router specified into the loader.
  • ErrorHandler(ErrorHandler) LoaderBuilder: See error handling.
  • AllowedMentions(*objects.AllowedMentions) LoaderBuilder: See allowed mentions.

At the end of this, just call Build with your interactions application (you probably want a *interactions.App from Postcord/interactions). This will automatically inject the routers into your application and build them with the appropriate allowed mentions configuration.

Error Handling

So how does error handling work? Error handling is done at a global scope with an error handler that takes a error parameter and returns a *objects.InteractionResponse. This can be used to write your own error handling code for actions. Note that there are a few errors that are dispatched by this codebase, and these are documented in the godoc for this project.

Allowed Mentions

Allowed mention configurations can be set on a command, group, and global scope. Note that it takes affect in that order, so a command level allowed mentions configuration will override a global one.

# Functions

DoubleAutoCompleteFuncBuilder is used to create a shorthand for adding a auto-complete function.
DoubleStaticChoicesBuilder is used to create a shorthand for adding choices.
IntAutoCompleteFuncBuilder is used to create a shorthand for adding a auto-complete function.
IntStaticChoicesBuilder is used to create a shorthand for adding choices.
RouterLoader is used to create a new router loader builder.
StringAutoCompleteFuncBuilder is used to create a shorthand for adding a auto-complete function.
StringStaticChoicesBuilder is used to create a shorthand for adding choices.
TestAutocomplete is used to run unit tests against the specified commands auto-complete.
TestCommand is used to run unit tests against the specified command.
TestComponent is used to run unit tests against the specified component.

# Variables

CommandDoesNotExist is thrown when the command specified does not exist.
CommandIsNotSubcommand is thrown when the router expects a command and gets a command group.
CommandIsSubcommand is thrown when the router expects a command group and gets a command.
GroupNestedTooDeep is thrown when the sub-command group would be nested too deep.
InvalidTarget is thrown when the command target is not valid.
MiddlewareChainExhausted is called when the middleware chain has been exhausted.
MismatchedOption is thrown when the option types mismatch.
ModalPathNotFound is thrown when the modal path is not found.
MultipleModalResponses is thrown when a modal response is triggered within another.
NoAutoCompleteFunc is thrown when Discord sends a focused argument without an autocomplete function.
NoCommandResponse is thrown when the application doesn't respond for a command.
NonExistentOption is thrown when an option is provided in an interaction that doesn't exist in the command.
NotButton is returned when Discord returns data that is not a button.
NotSelectionMenu is returned when Discord returns data that is not a selection menu.
UnknownContextType is thrown when a context type is not from Postcord.
UnsetModalRouter is thrown when the modal router is unset.

# Structs

CombinedRouter is an extension of both CommandRouter and ComponentRouter to combine the two.
Command is used to define a Discord (sub-)command.
CommandGroup is a group of commands.
No description provided by the author
CommandRouter is used to route commands.
CommandRouterCtx is used to define the commands context from the router.
ComponentRouter is used to route components.
ComponentRouterCtx is used to define a components router context.
DoubleChoice is used to define a choice of the double type.
IntChoice is used to define a choice of the int type.
MiddlewareCtx is used to define the additional context that is shared between middleware.
ModalContent defines the content of the modal.
ModalContentItem is used to define a item in a modal.
ModalGenerationCtx is used to generate a modal.
ModalRouter is used to route modals.
ModalRouterCtx is used to define the context for the modal event.
StringChoice is used to define a choice of the string type.

# Interfaces

CommandBuilder is used to define a builder for a Command object where the type isn't known.
HandlerAccepter is an interface for an object which accepts Postcord handler functions.
LoaderBuilder is the interface for a router loader builder.
MessageCommandBuilder is used to define a builder for a Message object where the type is a user command.
Resolvable is the type which is used for all resolvable items.
ResolvableMentionable is a special type that *mostly* implements the Resolvable interface but does not return a pointer for resolve.
ResolvableUser is used to define a user in a command option that is potentially resolvable.
ResponseDataBuilder is used to.
SubCommandBuilder is similar to TextCommandBuilder but doesn't allow default permissions to be set.
TestingT is our internal requirements from *testing.T.
TextCommandBuilder is used to define a builder for a Command object where the type is a text command.
UserCommandBuilder is used to define a builder for a Command object where the type is a user command.

# Type aliases

ButtonFunc is the function dispatched when a button is used.
DoubleAutoCompleteFunc is used to define the auto-complete function for DoubleChoice.
DoubleChoiceBuilder is used to choose how this choice is handled.
ErrorHandler defines the error handler function used within Postcord.
IntAutoCompleteFunc is used to define the auto-complete function for IntChoice.
IntChoiceBuilder is used to choose how this choice is handled.
MiddlewareFunc is used to define a middleware function.
SelectMenuFunc is the function dispatched when a select menu is used.
StringAutoCompleteFunc is used to define the auto-complete function for StringChoice.
StringChoiceBuilder is used to choose how this choice is handled.