Documentation ¶
Overview ¶
Package bot provides the Bot handling all commands.
Index ¶
- Variables
- func DefaultErrorHandler(err error, s *state.State, ctx *plugin.Context)
- func DefaultGatewayErrorHandler(err error)
- func DefaultPanicHandler(recovered interface{}, s *state.State, ctx *plugin.Context)
- func DefaultThrottlerCancelCheck(err error) bool
- func FilterGatewayError(err error) bool
- type Bot
- func (b *Bot) AddCommand(cmd plugin.Command)
- func (b *Bot) AddIntents(i gateway.Intents)
- func (b *Bot) AddModule(mod plugin.Module)
- func (b *Bot) AddPluginSource(name string, f PluginSourceFunc)
- func (b *Bot) AddPostMiddleware(f interface{})
- func (b *Bot) Close(ctx context.Context) error
- func (b *Bot) Open(timeout time.Duration) error
- func (b *Bot) Route(base *event.Base, msg *discord.Message, member *discord.Member)
- func (b *Bot) TryAddPostMiddleware(f interface{}) error
- type CommandFunc
- func CheckBotPermissions(next CommandFunc) CommandFunc
- func CheckChannelTypes(next CommandFunc) CommandFunc
- func CheckHuman(next CommandFunc) CommandFunc
- func CheckMessageType(next CommandFunc) CommandFunc
- func CheckPrefix(next CommandFunc) CommandFunc
- func CheckRestrictions(next CommandFunc) CommandFunc
- func FindCommand(next CommandFunc) CommandFunc
- func InvokeCommand(next CommandFunc) CommandFunc
- func ParseArgs(next CommandFunc) CommandFunc
- func SendTyping(next CommandFunc) CommandFunc
- type Middleware
- type MiddlewareManager
- type Middlewarer
- type Options
- type PluginSourceFunc
- type ReplyTypeError
- type SettingsProvider
Constants ¶
This section is empty.
Variables ¶
var ErrMiddleware = errors.New("the passed function does not resemble a valid middleware")
ErrMiddleware is the error returned if a middleware given to MiddlewareManager.TryAddMiddleware is not a valid middleware type.
var ErrUnknownCommand = errors.NewUserErrorl(unknownCommandErrorDescription)
ErrUnknownCommand is the error used if a message with a matching prefix does not contain a valid command invoke.
Functions ¶
func DefaultGatewayErrorHandler ¶
func DefaultGatewayErrorHandler(err error)
func DefaultPanicHandler ¶
func DefaultThrottlerCancelCheck ¶
DefaultThrottlerCancelCheck checks if the error is an *InformationalError. If so, it returns false otherwise it returns true.
func FilterGatewayError ¶
FilterGatewayError filters out informational reconnect errors.
Types ¶
type Bot ¶
type Bot struct { State *state.State MiddlewareManager Owners []discord.UserID EditAge time.Duration ErrorHandler func(error, *state.State, *plugin.Context) PanicHandler func(recovered interface{}, s *state.State, ctx *plugin.Context) MessageCreateMiddlewares []interface{} MessageUpdateMiddlewares []interface{} // contains filtered or unexported fields }
Bot is the bot executing all commands.
func (*Bot) AddCommand ¶
AddCommand adds the passed top-level command to the bot.
func (*Bot) AddIntents ¶
AddIntents adds the passed gateway.Intents to the bot.
func (*Bot) AddModule ¶
AddModule adds the passed top-level module to the Bot.
If automatic handler adding is enabled, all methods of the Module representing a handler func will be added to the State's event handler. The same goes for all sub-modules and sub-commands of the module.
func (*Bot) AddPluginSource ¶
func (b *Bot) AddPluginSource(name string, f PluginSourceFunc)
AddPluginSource adds the passed PluginSourceFunc under the passed unique name. The name is similar to a key and can be used later on to distinguish between different plugin sources. It is typically snake_case.
'built_in' is reserved for built-in plugins, and AddPluginSource will panic if attempting to use it.
The plugin sources will be used in the order they are added in.
func (*Bot) AddPostMiddleware ¶
func (b *Bot) AddPostMiddleware(f interface{})
AddPostMiddleware is the same as TryAddPostMiddleware, but panics if TryAddPostMiddleware returns an error.
func (*Bot) Close ¶
Close closes all gateways handled by the bot.
If an error occurs, Close will attempt to close all remaining gateways first, before returning. If multiple errors occur during that process, a MultiError will be returned.
The passed context will only be checked while waiting for all event handlers to finish. Even if the context expires, Close guarantees that all gateways are closed, except if errors occurred.
func (*Bot) Open ¶
Open opens a connection to the gateway and starts the bot.
If no gateway.Intents were added to the State before opening, Open will derive intents from the registered handlers.
gateway.IntentGuildMessages and gateway.IntentDirectMessages will always be added. Additionally, gateway.IntentGuilds will be added, if guild caching is enabled.
Refer to the doc of State.Open to understand how the timeout is applied.
func (*Bot) Route ¶
Route attempts to route the passed message. It aborts if the message is not a valid invoke.
When calling the bot's middlewares, it guarantees that Message, Member, Base, BotOwnerIDs, Replier, Provider, DiscordDataProvider, and ErrorHandler are set. Further, Localizer will be set to a fallback localizer.
func (*Bot) TryAddPostMiddleware ¶
TryAddPostMiddleware adds a middleware to the Bot that is invoked after all command and module middlewares were called. The order of invocation of post middlewares is the same as the order they were added in.
If the middleware's type is invalid, TryAddMiddleware will return ErrMiddleware.
Valid middleware types are:
- func(*state.State, interface{})
- func(*state.State, interface{}) error
- func(*state.State, *event.Base)
- func(*state.State, *event.Base) error
- func(*state.State, *state.MessageCreateEvent)
- func(*state.State, *state.MessageCreateEvent) error
- func(*state.State, *state.MessageUpdateEvent)
- func(*state.State, *state.MessageUpdateEvent) error
- func(next CommandFunc) CommandFunc
type CommandFunc ¶
CommandFunc is the signature of the Invoke function of a plugin.Command, without the reply (interface{}) return.
func CheckBotPermissions ¶
func CheckBotPermissions(next CommandFunc) CommandFunc
CheckBotPermissions checks if the discord.Permissions the bot requires for the command are satisfied.
func CheckChannelTypes ¶
func CheckChannelTypes(next CommandFunc) CommandFunc
CheckChannelTypes checks if the plugin.ChannelTypes of the command are satisfied.
func CheckHuman ¶
func CheckHuman(next CommandFunc) CommandFunc
CheckHuman checks if the invoking message was written by a human. If so it calls the next middleware, otherwise it aborts with an *errors.InformationalError.
func CheckMessageType ¶
func CheckMessageType(next CommandFunc) CommandFunc
CheckMessageType checks if the invoking message is of type discord.DefaultMessage. If so it calls the next middleware, otherwise it aborts with an *errors.InformationalError.
func CheckPrefix ¶
func CheckPrefix(next CommandFunc) CommandFunc
CheckPrefix checks if the message starts with the prefix. The prefix must either be the mention of the bot, or one of the prefixes found in the context.
Direct messages don't require prefixes, however, if a message starts with a prefix, it will still be stripped from the invoke.
If the prefix doesn't match, an *errors.InformationalError will be returned.
The middleware sets the ctx.InvokeIndex context field.
func CheckRestrictions ¶
func CheckRestrictions(next CommandFunc) CommandFunc
CheckRestrictions checks if the command is restricted.
func FindCommand ¶
func FindCommand(next CommandFunc) CommandFunc
FindCommand attempts to find the command being invoked by the message. If no matching command is found, the middleware returns ErrUnknownCommand.
The middleware sets the InvokedCommand and ArgsIndex context fields.
func InvokeCommand ¶
func InvokeCommand(next CommandFunc) CommandFunc
InvokeCommand invokes the command and sends a reply, if the command returned one.
func ParseArgs ¶
func ParseArgs(next CommandFunc) CommandFunc
ParseArgs parses the ctx.RawArgs using the commands plugin.ArgConfig.
func SendTyping ¶
func SendTyping(next CommandFunc) CommandFunc
SendTyping sends a typing event every 6 seconds until the command finishes executing.
type Middleware ¶
type Middleware func(next CommandFunc) CommandFunc
Middleware is a middleware function.
func NewSettingsRetriever ¶
func NewSettingsRetriever(settingsProvider SettingsProvider) Middleware
NewSettingsRetriever creates a new settings retriever middleware that retrieves the settings from the passed SettingsProvider. If the settings provider returns !ok, the returned middleware will abort by returning an *errors.InformationalError.
The returned middleware will set the Prefixes and Localizer context fields.
func NewThrottlerChecker ¶
func NewThrottlerChecker(cancelChecker func(err error) bool) Middleware
NewThrottlerChecker creates a new bot.Middleware that checks if a command is being throttled. Additionally, it signals cancellation to the throttler.
type MiddlewareManager ¶
type MiddlewareManager struct {
// contains filtered or unexported fields
}
MiddlewareManager is a struct that can be embedded in commands and modules to provide middleware capabilities. It implements Middlewarer.
MiddlewareManagers zero value is an empty MiddlewareManager.
func (*MiddlewareManager) AddMiddleware ¶
func (m *MiddlewareManager) AddMiddleware(f interface{})
AddMiddleware is the same as TryAddMiddleware, but panics if TryAddMiddleware returns an error.
func (*MiddlewareManager) Middlewares ¶
func (m *MiddlewareManager) Middlewares() []Middleware
Middlewares returns the middlewares of the MiddlewareManager.
func (*MiddlewareManager) TryAddMiddleware ¶
func (m *MiddlewareManager) TryAddMiddleware(f interface{}) error
TryAddMiddleware adds the passed middleware to the MiddlewareManager. If the middleware's type is invalid, TryAddMiddleware will return ErrMiddleware.
Valid middleware types are:
- func(*state.State, interface{})
- func(*state.State, interface{}) error
- func(*state.State, *event.Base)
- func(*state.State, *event.Base) error
- func(*state.State, *state.MessageCreateEvent)
- func(*state.State, *state.MessageCreateEvent) error
- func(*state.State, *state.MessageUpdateEvent)
- func(*state.State, *state.MessageUpdateEvent) error
- func(next CommandFunc) CommandFunc
type Middlewarer ¶
type Middlewarer interface { // Middlewares returns the MiddlewareFuncs of the plugin. Middlewares() []Middleware }
Middlewarer is an abstraction of a plugin that provides middlewares. If a plugin does not implement the interface, it will be assumed that the plugin does not provide any middlewares.
type Options ¶
type Options struct { // Token is the bot token without the 'Bot ' prefix. // // This field is required. Token string // SettingsProvider is the settings provider for the bot. // If left nil, only the mention prefix will be usable. // // Default: StaticSettings() SettingsProvider SettingsProvider // Owners are the ids of the bot owners. // These are accessible through plugin.Context.BotOwnerIDs. // // Default: nil Owners []discord.UserID // EditAge is the oldest age an edit message may have, to trigger a // command. // If a message older than EditAge is edited, it will be ignored. // If this is set to 0 or less, edited messages won't be watched. // // Default: 0 EditAge time.Duration // Status is the status of the bot. // // Default: gateway.OnlineStatus Status discord.Status // ActivityType is the type of activity. // ActivityName must be set for this to take effect. // // Default: discord.GameActivity ActivityType discord.ActivityType // ActivityName is the name of the activity the bot will display, if any. // If this left empty, the bot won't display any activity. // // Default: None ActivityName string // ActivityURL is the URL of the activity. // Currently, this is only used if the activity is set to Streaming. // // Default: None ActivityURL discord.URL // ArgParser is the plugin.ArgParser used to parse the arguments of all // commands that don't define a custom one. // // Default: &arg.DelimiterParser{Delimiter: ','} ArgParser plugin.ArgParser // AllowBot specifies whether bots may trigger commands. // // Settings this field has no effect if NoDefaultMiddlewares is set to // true. // // Default: false AllowBot bool // ThrottlerCancelChecker is the function run every time a command returns // with a non-nil error. // If the function returns true, the command's throttler will not count the // invoke. // // Settings this field has no effect if NoDefaultMiddlewares is set to // true. // // Default: DefaultThrottlerCancelCheck ThrottlerCancelChecker func(error) bool // Cabinet is the store.Cabinet used for caching. // Use store.NoopCabinet to deactivate caching. // // Default: defaultstore.New() Cabinet *store.Cabinet // GatewayErrorHandler is the error handler of the gateway. // // Default: DefaultGatewayErrorHandler GatewayErrorHandler func(error) // StateErrorHandler is the error handler of the *state.State, called if an // event handler returns with an error. // // Default: func(err error) { log.Println("event handler:", err.String()) } StateErrorHandler func(error) // StatePanicHandler is the panic handler of the *state.State, called if an // event handler panics. // // Default: // func(rec interface{}) { // log.Printf("event handler: panic: %+v\n%s\n", rec) // } StatePanicHandler func(recovered interface{}) // ErrorHandler is the handler called if a command returns with a non-nil // error. // // Default: DefaultErrorHandler ErrorHandler func(error, *state.State, *plugin.Context) // PanicHandler is the handler called if a command panics. // // Default: DefaultPanicHandler PanicHandler func(recovered interface{}, s *state.State, ctx *plugin.Context) // HTTPClient is the http client that will be used to make requests. // // Default: httputil.NewClient() HTTPClient *httputil.Client // MessageCreateMiddlewares are the middlewares invoked before routing the // command, if the command was received through a message create event. // // The signature of the middleware funcs must satisfy the requirements // of state middlewares. MessageCreateMiddlewares []interface{} // MessageCreateMiddlewares are the middlewares invoked before routing the // command, if the command was received through a message update event. // // The signature of the middleware funcs must satisfy the requirements // of state middlewares. MessageUpdateMiddlewares []interface{} // TotalShards is the total number of shards. // If it is <= 0, the recommended number of shards will be used. TotalShards int // ShardIDs are the custom shard ids this Bot instance will use. // // If setting this, you also need to set TotalShards. // // Default: 0..TotalShards ShardIDs []int // Gateways are the initial gateways to use. // It is an alternative to TotalShards and ShardIDs, and you shouldn't set // both. Gateways []*gateway.Gateway // Rescale is the function called if Discord closes any of the gateways // with a 4011 close code aka. 'Sharding Required'. // // Usage // // To update the state's shard manager, you must call update. // All zero-value options in the Options you give to update, will be set to // the options you used when initially creating the state. // This does not apply to TotalShards, ShardIDs, and Gateways, which will // assume the defaults described in their respective documentation. // Furthermore, setting ErrorHandler or PanicHandler will have no effect. // // After calling update, you should reopen the state, by calling Open. // Alternatively, you can call open individually for State.Gateways(). // Note, however, that you should call Sate.Handler.Open(State.Events) once // before calling Gateway.Open, should you choose to open individually. // // During update, the state's State field will be replaced, as well as the // gateways and the rescale function. The event handler will remain // untouched which is why you don't need to readd your handlers. // // Default // // If you set neither TotalShards nor Gateways, this will default to the // below unless you define a custom Rescale function. // // func(update func(Options) *State) { // s, err := update(Options{}) // if err != nil { // log.Println("could not update state during rescale:", err.Error()) // return // } // // err = s.Open(context.Background()) // if err != nil { // log.Println("could not open state during rescale:", err.Error()) // } // } // // Otherwise, you are required to set this function yourself. Rescale func(update func(state.Options) (*state.State, error)) // NoDefaultMiddlewares, if true, does not add the default middlewares // upon creation of the bot. // These middlewares are responsible for validation as well as filling some // of the plugin.Context's fields. // // If setting this to true those checks, or equivalents of them, should be // manually added. // Although possible, it is highly discouraged to disable certain checks // unless the resulting behavior is explicitly desired, as default or // third-party plugins may rely on these checks in order to perform as // intended. // // When the first middleware is called not all fields of the context will // be set. // Instead, they are set by the default middlewares. // If you want to swap out a default middleware for a custom // implementation, refer to its doc to see which fields it sets. // // Also keep in mind that middlewares added after field-setting // middlewares, may rely on those field being set. // Fully removing a default middleware that sets some fields without // setting them otherwise is highly discouraged, as plugins will assume // all fields to be set. // // To see which fields are always set, i.e. which fields are available // to all middlewares, refer to the doc of Bot.Route. // // By default, the following middlewares are added upon creation of the // bot. // // Bot.AddMiddleware(CheckMessageType) // Bot.AddMiddleware(CheckHuman) // if Options.AllowBot is true // Bot.AddMiddleware(NewSettingsRetriever(Options.SettingsProvider)) // Bot.AddMiddleware(CheckPrefix) // Bot.AddMiddleware(FindCommand) // Bot.AddMiddleware(CheckChannelTypes) // Bot.AddMiddleware(CheckBotPermissions) // Bot.AddMiddleware(NewThrottlerChecker(Options.ThrottlerCancelChecker)) // // Bot.AddPostMiddleware(CheckRestrictions) // Bot.AddPostMiddleware(ParseArgs) // Bot.AddPostMiddleware(InvokeCommand) NoDefaultMiddlewares bool }
Options contains different configurations for a Bot.
func (*Options) SetDefaults ¶
SetDefaults fills the defaults for all options, that weren't manually set.
type PluginSourceFunc ¶
type PluginSourceFunc = resolved.PluginSourceFunc
A PluginSourceFunc is the function used to retrieve additional plugins from other sources only available at runtime. A typical example for this would be custom commands or tags.
PluginProviders will be called in the order they were added to a Bot, until one of the returns a matching plugin.
If there are no plugins to return, all return values should be nil. If there is an error the returned plugins will be discarded, and the error will be noted in the Context of the command, available via Context.UnavailablePluginSources().
type ReplyTypeError ¶
type ReplyTypeError struct {
Reply interface{}
}
ReplyTypeError is the error used if a reply returned by plugin.Command.Invoke is not of a supported types.
func (*ReplyTypeError) Error ¶
func (r *ReplyTypeError) Error() string
type SettingsProvider ¶
type SettingsProvider func(b *event.Base, m *discord.Message) (prefixes []string, localizer *i18n.Localizer, ok bool)
SettingsProvider is the function used to retrieve the settings for the guild or direct message.
The passed *event.Base is the base of the event triggering the settings check. This will either stem from a message create event, or a message update event, if Options.EditAge is greater than 0.
First Return Value ¶
The first return value contains the prefixes used by the guild or user. In a guild, the message must start with one of the prefixes or with a bot mention. Direct Messages are not subject to this limitation. However, if prefixes are returned for a direct message invoke and the user prefixes their message with one, the prefix will still be stripped. Similarly, if the user prefixes a direct message with the bot's mention, it will also get stripped. This behavior can be changed by replacing the CheckPrefix default middleware.
All spaces and newlines between prefix and the rest of the message will be removed before given to the router. If prefixes is empty, the only valid prefix will be a mention of the bot.
Prefix matching is non-exhaustive, meaning the first matching prefix will be used and the bot will not look for longer prefix that matches as well.
Second Return Value ¶
The second return value is the *1i8n.Localizer, used to generate translations. New localizers can be created using i18n.NewLocalizer.
Third Return Value ¶
The last return value is an ok-type bool. If false, the message will be discarded, regardless of whether there is a matching prefix. This intended for use in error scenarios, when no prefix or localizer can be obtained, and fallbacks are undesired.
Error Handling ¶
SettingsProvider intentionally uses a bool instead of an error return value to signal unsuccessful execution. This has two reasons.
Mainly, because it is not ensured if the message we are checking is even a command invoke. Suppose you are unable to retrieve your bots settings. This would lead to the bot responding to every message on every server it is with some sort of error.
Secondly, errors in adam are represented through errors.Error. However, to invoke errors.Error.Handle a plugin.Context is required, which at this point is not generated yet, because the message has not been identified as a command.
For those reasons, error handling is left implementation-specific, and you are responsible for ensuring that errors are properly captured.
func StaticSettings ¶
func StaticSettings(prefixes ...string) SettingsProvider
StaticSettings creates a new SettingsProvider that returns the same prefixes for all guilds and users. The returned localizer will always be a fallback localizer.