router.go 4.8 KB

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