router.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package mux
  2. import (
  3. "errors"
  4. "strings"
  5. "git.mgmcomp.net/thisnthat/discordgo"
  6. )
  7. // RouteOptions holds information about a specific message route handler
  8. type RouteOptions struct {
  9. Name string // match name that should trigger this route handler
  10. Description string // short description of this route
  11. Usage string // How to use the route
  12. Category string // The category to put the route under
  13. Type RouteType // The type of route this is
  14. Callback Handler // route handler function to call
  15. }
  16. type route struct {
  17. Name string
  18. Description string
  19. Usage string
  20. CategoryID int
  21. Type RouteType
  22. Run Handler
  23. }
  24. type category struct {
  25. Name string
  26. Description string
  27. ID int
  28. }
  29. // RouteType is the type of route being created
  30. type RouteType int
  31. const (
  32. // MessageRoute is a route for handling OnMessageCreate events
  33. MessageRoute RouteType = 1001
  34. )
  35. // Handler is the function signature required for a message route handler.
  36. type Handler func(*discordgo.Session, *discordgo.Message, *Context)
  37. // Context holds a bit of extra data we pass along to route handlers
  38. // This way processing some of this only needs to happen once.
  39. type Context struct {
  40. Fields []string
  41. Args []string
  42. Content string
  43. isDirectMessage bool // Indicates the message was sent via direct message
  44. Method Method
  45. }
  46. // Method is the method a command was received
  47. type Method int
  48. const (
  49. // DirectMethod Discord DM to the bot
  50. DirectMethod Method = 1001
  51. // MentionMethod is a message started with a @mention to the bot
  52. MentionMethod Method = 1002
  53. // PrefixMethod is a message started with a command prefix
  54. PrefixMethod Method = 1003
  55. )
  56. // Router is the main struct for all mux methods.
  57. type Router struct {
  58. routes []*route
  59. helpRoute *route
  60. prefix string
  61. categories []*category
  62. }
  63. // New returns a new Discord message route mux
  64. func New() *Router {
  65. r := &Router{}
  66. helpRoute := &route{}
  67. helpRoute.Name = "help"
  68. helpRoute.Usage = "help"
  69. helpRoute.Description = "Get Help"
  70. helpRoute.Run = r.helpCommandHandler
  71. r.helpRoute = helpRoute
  72. return r
  73. }
  74. // SetCommandPrefix will set the prefix used for message commands
  75. func (r *Router) SetCommandPrefix(cmdPrefix string) {
  76. r.prefix = cmdPrefix + " "
  77. }
  78. // ErrRegisterRouteNameRequired is returned when registering a new route without a name
  79. var ErrRegisterRouteNameRequired = errors.New("All routes must have a name")
  80. // ErrRegisterInvalidRouteType is returned when registering a new route with an invalid type
  81. var ErrRegisterInvalidRouteType = errors.New("Invalid route type")
  82. // ErrRegisterCallbackRequired is returned when registering a new route without a callback
  83. var ErrRegisterCallbackRequired = errors.New("A valid callback must be provided")
  84. // Register allows you to register a route
  85. //func (r *Router) Register(routeType RouteType, name, desc string, callback Handler) (*Route, error) {
  86. func (r *Router) Register(name string, options RouteOptions) error {
  87. if name == "" {
  88. return ErrRegisterRouteNameRequired
  89. }
  90. if !isValidRouteType(options.Type) {
  91. return ErrRegisterInvalidRouteType
  92. }
  93. if options.Callback == nil {
  94. return ErrRegisterCallbackRequired
  95. }
  96. route := route{}
  97. route.Type = options.Type
  98. route.Name = name
  99. route.Description = options.Description
  100. route.Usage = options.Usage
  101. route.Run = options.Callback
  102. if options.Category != "" {
  103. for _, category := range r.categories {
  104. if category.Name == options.Category {
  105. route.CategoryID = category.ID
  106. break
  107. }
  108. }
  109. }
  110. r.routes = append(r.routes, &route)
  111. return nil
  112. }
  113. // ErrAddCategoryNameRequired is returned when registering a new route without a name
  114. var ErrAddCategoryNameRequired = errors.New("All categories must have a name")
  115. // AddCategory allows you to a a router category
  116. func (r *Router) AddCategory(name, description string) error {
  117. if name == "" {
  118. return ErrAddCategoryNameRequired
  119. }
  120. category := category{}
  121. category.Name = name
  122. category.Description = description
  123. category.ID = len(r.categories) + 1
  124. r.categories = append(r.categories, &category)
  125. return nil
  126. }
  127. func isValidRouteType(routeType RouteType) bool {
  128. switch routeType {
  129. case MessageRoute:
  130. return true
  131. }
  132. return false
  133. }
  134. func (r *Router) findRoute(searchString string, routeType RouteType) (*route, []string, []string) {
  135. fields := strings.Fields(searchString)
  136. if len(fields) == 0 {
  137. return nil, nil, nil
  138. }
  139. commandKey := fields[0]
  140. for _, route := range r.routes {
  141. if route.Type != routeType {
  142. continue
  143. }
  144. if strings.ToLower(commandKey) == strings.ToLower(route.Name) {
  145. return route, fields[0:], fields[1:]
  146. }
  147. }
  148. return nil, nil, nil
  149. }