shireikan

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 26, 2021 License: MIT Imports: 9 Imported by: 2

README

shireikan   CI Coverage Status Go Report Card

司令官 - A prototype, object-oriented command handler for discordgo.

This is a work-in-progress command handler which shall later replace the current command handler used in shinpuru.

If you are interested how to use this package, see the basic example.

This command handler is strongly inspired by Lukaesebrot's package dgc.


Example

package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/bwmarrin/discordgo"
	"github.com/zekroTJA/shireikan"
)

type UsernameMiddleware struct{}

func (m *UsernameMiddleware) Handle(cmd shireikan.Command, ctx shireikan.Context, layer shireikan.MiddlewareLayer) (bool, error) {
	ctx.SetObject("username", ctx.GetUser().Username)
	return true, nil
}

func (m *UsernameMiddleware) GetLayer() shireikan.MiddlewareLayer {
	return shireikan.LayerBeforeCommand
}

type HelloCommand struct {
}

func (c *HelloCommand) GetInvokes() []string {
	return []string{"hello", "hey"}
}

func (c *HelloCommand) GetDescription() string {
	return "Greets you or another user!"
}

func (c *HelloCommand) GetHelp() string {
	return "`hello` - greets you\n" +
		"`hello <username>` - greets someone else"
}

func (c *HelloCommand) GetGroup() string {
	return shireikan.GroupEtc
}

func (c *HelloCommand) GetDomainName() string {
	return "test.etc.hellp"
}

func (c *HelloCommand) GetSubPermissionRules() []shireikan.SubPermission {
	return nil
}

func (c *HelloCommand) IsExecutableInDMChannels() bool {
	return true
}

func (c *HelloCommand) Exec(ctx shireikan.Context) error {
	var username string
	if username = ctx.GetArgs().Get(0).AsString(); username == "" {
		// Get username from middleware
		username, _ = ctx.GetObject("username").(string)
	}
	_, err := ctx.Reply(fmt.Sprintf("Hello, %s!", username))
	return err
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}

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

	session, err := discordgo.New("Bot " + token)
	must(err)

	must(session.Open())

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

	handler := shireikan.New(&shireikan.Config{
		GeneralPrefix:         "!",
		AllowBots:             false,
		AllowDM:               true,
		ExecuteOnEdit:         true,
		InvokeToLower:         true,
		UseDefaultHelpCommand: true,
		OnError: func(ctx shireikan.Context, typ shireikan.ErrorType, err error) {
			log.Printf("[ERR] [%d] %s", typ, err.Error())
		},
	})

	handler.Register(&UsernameMiddleware{})
	handler.Register(&HelloCommand{})

	handler.Setup(session)
}

You can find more complex examples in the examples/ directory.

shireikan is used in my own Discord bot shinpuru. Take a look if you want to see a "real world" implementation example. 😉


© 2020-2021 Ringo Hoffmann (zekro Development).
Covered by the MIT Licence.

Documentation

Overview

Package shireikan provides a general command handler for discordgo.

Index

Constants

View Source
const (
	GroupGlobalAdmin = "GLOBAL ADMIN" // Global Admin Group
	GroupGuildAdmin  = "GUILD ADMIN"  // Guild Admin Group
	GroupModeration  = "MODERATION"   // Moderation Untilities Group
	GroupFun         = "FUN"          // Fun Group
	GroupGame        = "GAME"         // Game Group
	GroupChat        = "CHAT"         // Chat Group
	GroupEtc         = "ETC"          // Etc. Group
	GroupGeneral     = "GENERAL"      // General Group
	GroupGuildConfig = "GUILD CONFIG" // Guild Config Group
)
View Source
const (
	VERSION = "0.6.0" // The package version.

	ObjectMapKeyHandler = "cmdhandler" // Handler instance object map key.
)

Variables

View Source
var (
	// Error returned when a command was not found.
	ErrCommandNotFound = errors.New("command not found")
	// Error returned when command was executed in a
	// DM channel which shall not be executed in a DM
	// channel.
	ErrCommandNotExecutableInDMs = errors.New("command is not executable in DM channels")

	EmbedColorDefault = 0x03A9F4 // Default Embed Color
	EmbedColorError   = 0xe53935 // Error Embed Color
)

Functions

This section is empty.

Types

type Argument

type Argument string

Argument extends string to provide general transformation functionality.

func (Argument) AsBool

func (a Argument) AsBool() (bool, error)

AsBool tries to parse the given argument as bool. If this fails, an error is returned.

As described in the strconv.ParseBool docs, the following values are accepted: "It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. Any other value returns an error."

func (Argument) AsFloat64

func (a Argument) AsFloat64() (float64, error)

AsFloat64 tries to parse the given argument as float64. If this fails, an error is returned.

func (Argument) AsInt

func (a Argument) AsInt() (int, error)

AsInt tries to parse the given argument as integer. If this fails, an error is returned.

func (Argument) AsString

func (a Argument) AsString() string

AsString returns the argument as string.

type ArgumentList

type ArgumentList []string

ArgumentList wraps a string list to get arguments in that list as Argument object.

func (ArgumentList) Contains

func (al ArgumentList) Contains(v string) bool

Contains returns true when v is included in arr.

func (ArgumentList) Get

func (al ArgumentList) Get(i int) Argument

Get returns the Argument at the given Index. If there is no argument at that index, an empty string is returned.

func (ArgumentList) IndexOf

func (al ArgumentList) IndexOf(v string) int

IndexOf returns the index of v in arr. If not found, the returned index is -1.

func (ArgumentList) Splice

func (al ArgumentList) Splice(i, r int) ArgumentList

Splice returns a new array sliced at i by the range of r.

type Command

type Command interface {
	// GetInvokes returns the unique strings udes to
	// call the command. The first invoke is the
	// primary command invoke and each following is
	// treated as command alias.
	GetInvokes() []string

	// GetDescription returns a brief description about
	// the functionality of the command.
	GetDescription() string

	// GetHelp returns detailed information on how to
	// use the command and their sub commands.
	GetHelp() string

	// GetGroup returns the group name of the command.
	GetGroup() string

	// GetDomainName returns the commands domain name.
	// The domain name is specified like following:
	//   sp.{group}(.{subGroup}...).{primaryInvoke}
	GetDomainName() string

	// GetSubPermissionRules returns optional sub
	// permissions of the command.
	GetSubPermissionRules() []SubPermission

	// IsExecutableInDMChannels returns true when
	// the command can be used in DM channels;
	// otherwise returns false.
	IsExecutableInDMChannels() bool

	// Exec is called when the command is executed and
	// is getting passed the command CommandArgs.
	// When the command was executed successfully, it
	// should return nil. Otherwise, the error
	// encountered should be returned.
	Exec(ctx Context) error
}

Command describes the functionalities of a command struct which can be registered in the CommandHandler.

type Config

type Config struct {
	GeneralPrefix         string `json:"general_prefix"`           // General and globally accessible prefix
	InvokeToLower         bool   `json:"invoke_to_lower"`          // Lowercase command invoke befor map matching
	AllowDM               bool   `json:"allow_dm"`                 // Allow commands to be executed in DM and GroupDM channels
	AllowBots             bool   `json:"allow_bots"`               // Allow bot accounts to execute commands
	ExecuteOnEdit         bool   `json:"execute_on_edit"`          // Execute command handler when a message was edited
	UseDefaultHelpCommand bool   `json:"use_default_help_command"` // Whether or not to use default help command
	DeleteMessageAfter    bool   `json:"delete_message_after"`     // Delete command message after command has processed

	// Optionally, you can pass a di.Container to obtain
	// instances from in the command context.
	ObjectContainer di.Container `json:"-"`

	// OnError is called when the command handler failed
	// or retrieved an error form a middleware or command
	// exec handler.
	//
	// The OnError handler is getting passed the context
	// (which may be incompletely initialized!), an
	// ErrorType and the error object.
	OnError func(ctx Context, errTyp ErrorType, err error)

	// GuildPrefixGetter is called to retrieve a guilds
	// specific prefix.
	//
	// The function is getting passed the guild's ID and
	// returns the guild prefix, when specified. The returned
	// string is empty when no guild prefix is specified.
	// An error is only returned when the retrieving of the
	// guild prefix failed unexpectedly.
	GuildPrefixGetter func(guildID string) (string, error)

	// State is the used implementation of a state cache.
	//
	// Defautly, the internal discordgo.State implementation
	// (state.Internal) is used. If you are using zekrotja/dgrs,
	// you can use the state.Dgrs state implementation. You can
	// also create and use a custom state implementation by
	// implementing the state.State interface.
	State state.State
}

Config wraps configuration values for the CommandHandler.

type Context

type Context interface {
	ObjectMap

	// GetSession returns the current discordgo.Session.
	GetSession() *discordgo.Session

	// GetArgs returns an ArgumentList of
	// the parsed command arguments.
	GetArgs() ArgumentList

	// GetChannel returns the channel where
	// the command message was sent into.
	GetChannel() *discordgo.Channel

	// GetMessage returns the original
	// message object of the command.
	GetMessage() *discordgo.Message

	// GetGuild returns the guild object
	// where the command was sent.
	GetGuild() *discordgo.Guild

	// GetMember returns the user object
	// of the author of the command message.
	GetUser() *discordgo.User

	// GetMember returns the member object
	// of the author of the command message.
	GetMember() *discordgo.Member

	// IsDM returns true when the command
	// message was sent into a DM or
	// GroupDM channel.
	IsDM() bool

	// IsEdit returns true if the event which
	// invoked the command was a
	// discordgo.MessageUpdate event.
	IsEdit() bool

	// Reply sends a message with the passed content
	// to the channel where the command was sent into.
	Reply(content string) (*discordgo.Message, error)

	// Reply sends a message with the passed embed
	// to the channel where the command was sent into.
	ReplyEmbed(embed *discordgo.MessageEmbed) (*discordgo.Message, error)

	// ReplyEmbedError sends a pre-constructed embed
	// as error message to the channel where the command
	// was sent into.
	ReplyEmbedError(content, title string) (*discordgo.Message, error)
}

Context wraps information about a message and the environment where the message was created which is passed to middleware and command handlers.

type ErrorType

type ErrorType int

ErrorType is the type of error occurred in the command message handler.

const (
	ErrTypGuildPrefixGetter    ErrorType = iota // Error from guild prefix getter function
	ErrTypGetChannel                            // Error getting channel object
	ErrTypGetGuild                              // Error getting guild object
	ErrTypCommandNotFound                       // Command was not found by specified invoke
	ErrTypNotExecutableInDM                     // Command which is specified as non-executable in DM got executed in a DM channel
	ErrTypMiddleware                            // Middleware handler returned an error
	ErrTypCommandExec                           // Command handler returned an error
	ErrTypDeleteCommandMessage                  // Deleting command message failed
	ErrTypeState                                // State action failed
)

type Handler

type Handler interface {
	ReadonlyObjectMap

	// Register is shorthand for RegisterMiddleware
	// or RegisterCommand and automatically choses
	// depending on the implementation the required
	// registration method.
	//
	// Panics if an instance is passed which neither
	// implements Command nor Middleware interface.
	Register(v interface{})

	// RegisterCommand registers the passed
	// Command instance.
	RegisterCommand(cmd Command)

	// RegisterMiddleware registers the
	// passed middleware instance.
	RegisterMiddleware(mw Middleware)

	// RegisterHandlers IS DEPRECATED!
	// Please use Setup(*Session) instead!
	//
	// RegisterHandlers registers the message
	// handlers to the passed discordgo.Session
	// which are used to handle and parse commands.
	RegisterHandlers(session *discordgo.Session)

	// Setup registers the message handlers to
	// the passed discordgo.Session which are
	// used to handle and parse commands.
	Setup(session *discordgo.Session)

	// GetConfig returns the specified config
	// object which was specified on intialization.
	GetConfig() *Config

	// GetCommandMap returns the internal command
	// map.
	GetCommandMap() map[string]Command

	// GetCommandInstances returns an array of all
	// registered command instances.
	GetCommandInstances() []Command

	// GetCommand returns a command instance form
	// the command register by invoke. If the
	// command could not be found, false is returned.
	GetCommand(invoke string) (Command, bool)
}

Handler specifies a command register and handler.

func New added in v0.5.0

func New(cfg *Config) Handler

New returns a new instance of the default command Handler implementation.

func NewHandler

func NewHandler(cfg *Config) Handler

NewHandler IS DEPRECATED! Please use New(*Config) instead!

type Middleware

type Middleware interface {

	// Handle is called right before the execution of
	// the command handler and is getting passed the
	// Command instance and the Context. Also, it is
	// getting passed the layer where the handler was
	// executed.
	//
	// When the returned bool is false, the following
	// command handler will not be executed.
	//
	// An error should only be returned when the
	// execution of the middleware handler failed
	// unexpectedly.
	Handle(cmd Command, ctx Context, layer MiddlewareLayer) (bool, error)

	// GetLayer returns the layer(s) when the middleware
	// shall be executed.
	//
	// This value is defined as a bitmask value, so you
	// can combine multiple layers to execute the
	// middleware at multiple points during command
	// handling.
	GetLayer() MiddlewareLayer
}

Middleware specifies a command middleware.

type MiddlewareLayer added in v0.2.0

type MiddlewareLayer int

MiddlewareLayer defines the layer when the middleware handler shall be executed during command parsing and handling.

const (
	// Execute right before command handler is executed.
	LayerBeforeCommand MiddlewareLayer = 1 << iota
	// Execute right after command handler was executed successfully.
	LayerAfterCommand
)

type ObjectMap added in v0.6.0

type ObjectMap interface {
	ReadonlyObjectMap

	// SetObject sets a value to the object
	// map linked with the given key.
	SetObject(key string, value interface{})
}

ObjectMap provides a thread save key-value map to set values to and get values from back.

type ReadonlyObjectMap added in v0.6.0

type ReadonlyObjectMap interface {

	// GetObject returns a value from the
	// object map by its key.
	//
	// Returns 'nil' when no object is stored
	// with the given key.
	GetObject(key string) interface{}

	// SetObject IS DEPRECTAED and will be
	// removed in later versions!
	//
	// SetObject sets a value to the object
	// map linked with the given key.
	SetObject(key string, value interface{})
}

ReadonlyObjectMap provides a thread save key-value map to get previously set items from.

type SubPermission

type SubPermission struct {
	Term        string `json:"term"`
	Explicit    bool   `json:"explicit"`
	Description string `json:"description"`
}

SubPermission wraps information about a sub permissions of commands.

Directories

Path Synopsis
examples
di
middleware

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL