123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- package discordbot
- import (
- "errors"
- "strings"
- "github.com/bwmarrin/discordgo"
- )
- // RouteOptions holds information about a specific message route handler
- type RouteOptions struct {
- Name string // match name that should trigger this route handler
- Description string // short description of this route
- Usage string // How to use the route
- Category string // The category to put the route under
- Type RouteType // The type of route this is
- Callback Handler // route handler function to call
- Hidden bool // The route is hidden from the help menu'
- Admin bool // The route is only visible to admins
- }
- type route struct {
- Name string
- Description string
- Usage string
- CategoryID int
- Type RouteType
- Run Handler
- Hidden bool
- Admin bool
- }
- type category struct {
- Name string
- Description string
- ID int
- }
- // RouteType is the type of route being created
- type RouteType int
- const (
- // MessageRoute is a route for handling OnMessageCreate events
- MessageRoute RouteType = 1001
- )
- // Handler is the function signature required for a message route handler.
- type Handler func(*discordgo.Session, *discordgo.Message, *Context)
- type IsAdminRouteHandler func(*discordgo.Session, *discordgo.Message, *Context) bool
- // Context holds a bit of extra data we pass along to route handlers
- // This way processing some of this only needs to happen once.
- type Context struct {
- Fields []string
- Args []string
- Content string
- Method Method
- }
- // Method is the method a command was received
- type Method int
- const (
- // DirectMethod Discord DM to the bot
- DirectMethod Method = 1001
- // MentionMethod is a message started with a @mention to the bot
- MentionMethod Method = 1002
- // PrefixMethod is a message started with a command prefix
- PrefixMethod Method = 1003
- )
- // Router is the main struct for all mux methods.
- type LegacyRouter struct {
- routes []*route
- helpRoute *route
- prefix string
- categories []*category
- isAdminRoute IsAdminRouteHandler // the admin check handler func to call
- forcePrefixMethod bool
- }
- // New returns a new Discord message route mux
- func NewLegacyRouter() *LegacyRouter {
- r := new(LegacyRouter)
- r.isAdminRoute = isAdminRouteDefault
- helpRoute := &route{}
- helpRoute.Name = "help"
- helpRoute.Usage = "help"
- helpRoute.Description = "Get Help"
- helpRoute.Run = r.helpCommandHandler
- r.helpRoute = helpRoute
- return r
- }
- // SetCommandPrefix will set the prefix used for message commands
- func (r *LegacyRouter) SetCommandPrefix(cmdPrefix string) {
- r.prefix = cmdPrefix + " "
- }
- func (r *LegacyRouter) SetAdminRouteCallback(callback IsAdminRouteHandler) {
- r.isAdminRoute = callback
- }
- func (r *LegacyRouter) ForcePrefixMethod(force bool) {
- r.forcePrefixMethod = force
- }
- // ErrRegisterRouteNameRequired is returned when registering a new route without a name
- var ErrRegisterRouteNameRequired = errors.New("all routes must have a name")
- // ErrRegisterInvalidRouteType is returned when registering a new route with an invalid type
- var ErrRegisterInvalidRouteType = errors.New("invalid route type")
- // ErrRegisterCallbackRequired is returned when registering a new route without a callback
- var ErrRegisterCallbackRequired = errors.New("a valid callback must be provided")
- // Register allows you to register a route
- // func (r *LegacyRouter) Register(routeType RouteType, name, desc string, callback Handler) (*Route, error) {
- func (r *LegacyRouter) Register(name string, options RouteOptions) error {
- if name == "" {
- return ErrRegisterRouteNameRequired
- }
- if !isValidRouteType(options.Type) {
- return ErrRegisterInvalidRouteType
- }
- if options.Callback == nil {
- return ErrRegisterCallbackRequired
- }
- route := route{}
- route.Type = options.Type
- route.Name = name
- route.Description = options.Description
- route.Usage = options.Usage
- route.Run = options.Callback
- route.Hidden = options.Hidden
- route.Admin = options.Admin
- if options.Category != "" {
- for _, category := range r.categories {
- if category.Name == options.Category {
- route.CategoryID = category.ID
- break
- }
- }
- }
- r.routes = append(r.routes, &route)
- return nil
- }
- // ErrAddCategoryNameRequired is returned when registering a new route without a name
- var ErrAddCategoryNameRequired = errors.New("all categories must have a name")
- // AddCategory allows you to a a router category
- func (r *LegacyRouter) AddCategory(name, description string) error {
- if name == "" {
- return ErrAddCategoryNameRequired
- }
- category := category{}
- category.Name = name
- category.Description = description
- category.ID = len(r.categories) + 1
- r.categories = append(r.categories, &category)
- return nil
- }
- func isValidRouteType(routeType RouteType) bool {
- switch routeType {
- case MessageRoute:
- return true
- }
- return false
- }
- func (r *LegacyRouter) findRoute(searchString string, routeType RouteType) (*route, []string, []string) {
- fields := strings.Fields(searchString)
- if len(fields) == 0 {
- return nil, nil, nil
- }
- commandKey := fields[0]
- for _, route := range r.routes {
- if route.Type != routeType {
- continue
- }
- if strings.EqualFold(commandKey, route.Name) {
- return route, fields[0:], fields[1:]
- }
- }
- return nil, nil, nil
- }
- // Default callback for determining if the caller is an admin
- func isAdminRouteDefault(s *discordgo.Session, m *discordgo.Message, ctx *Context) bool {
- channelPermissions, err := s.UserChannelPermissions(m.Author.ID, m.ChannelID)
- if err != nil {
- return false
- }
- return (channelPermissions&discordgo.PermissionAdministrator > 0)
- }
|