event.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package discordgo
  2. import "fmt"
  3. // EventHandler is an interface for Discord events.
  4. type EventHandler interface {
  5. // Type returns the type of event this handler belongs to.
  6. Type() string
  7. // Handle is called whenever an event of Type() happens.
  8. // It is the recievers responsibility to type assert that the interface
  9. // is the expected struct.
  10. Handle(*Session, interface{})
  11. }
  12. // EventInterfaceProvider is an interface for providing empty interfaces for
  13. // Discord events.
  14. type EventInterfaceProvider interface {
  15. // Type is the type of event this handler belongs to.
  16. Type() string
  17. // New returns a new instance of the struct this event handler handles.
  18. // This is called once per event.
  19. // The struct is provided to all handlers of the same Type().
  20. New() interface{}
  21. }
  22. // interfaceEventType is the event handler type for interface{} events.
  23. const interfaceEventType = "__INTERFACE__"
  24. // interfaceEventHandler is an event handler for interface{} events.
  25. type interfaceEventHandler func(*Session, interface{})
  26. // Type returns the event type for interface{} events.
  27. func (eh interfaceEventHandler) Type() string {
  28. return interfaceEventType
  29. }
  30. // Handle is the handler for an interface{} event.
  31. func (eh interfaceEventHandler) Handle(s *Session, i interface{}) {
  32. eh(s, i)
  33. }
  34. var registeredInterfaceProviders = map[string]EventInterfaceProvider{}
  35. // registerInterfaceProvider registers a provider so that DiscordGo can
  36. // access it's New() method.
  37. func registerInterfaceProvider(eh EventInterfaceProvider) error {
  38. if _, ok := registeredInterfaceProviders[eh.Type()]; ok {
  39. return fmt.Errorf("event %s already registered", eh.Type())
  40. }
  41. registeredInterfaceProviders[eh.Type()] = eh
  42. return nil
  43. }
  44. // eventHandlerInstance is a wrapper around an event handler, as functions
  45. // cannot be compared directly.
  46. type eventHandlerInstance struct {
  47. eventHandler EventHandler
  48. }
  49. // addEventHandler adds an event handler that will be fired anytime
  50. // the Discord WSAPI matching eventHandler.Type() fires.
  51. func (s *Session) addEventHandler(eventHandler EventHandler) func() {
  52. s.handlersMu.Lock()
  53. defer s.handlersMu.Unlock()
  54. if s.handlers == nil {
  55. s.handlers = map[string][]*eventHandlerInstance{}
  56. }
  57. ehi := &eventHandlerInstance{eventHandler}
  58. s.handlers[eventHandler.Type()] = append(s.handlers[eventHandler.Type()], ehi)
  59. return func() {
  60. s.removeEventHandlerInstance(eventHandler.Type(), ehi)
  61. }
  62. }
  63. // addEventHandler adds an event handler that will be fired the next time
  64. // the Discord WSAPI matching eventHandler.Type() fires.
  65. func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
  66. s.handlersMu.Lock()
  67. defer s.handlersMu.Unlock()
  68. if s.onceHandlers == nil {
  69. s.onceHandlers = map[string][]*eventHandlerInstance{}
  70. }
  71. ehi := &eventHandlerInstance{eventHandler}
  72. s.onceHandlers[eventHandler.Type()] = append(s.onceHandlers[eventHandler.Type()], ehi)
  73. return func() {
  74. s.removeEventHandlerInstance(eventHandler.Type(), ehi)
  75. }
  76. }
  77. // AddHandler allows you to add an event handler that will be fired anytime
  78. // the Discord WSAPI event that matches the function fires.
  79. // events.go contains all the Discord WSAPI events that can be fired.
  80. // eg:
  81. // Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
  82. // })
  83. //
  84. // or:
  85. // Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
  86. // })
  87. // The return value of this method is a function, that when called will remove the
  88. // event handler.
  89. func (s *Session) AddHandler(handler interface{}) func() {
  90. eh := handlerForInterface(handler)
  91. if eh == nil {
  92. s.log(LogError, "Invalid handler type, handler will never be called")
  93. return func() {}
  94. }
  95. return s.addEventHandler(eh)
  96. }
  97. // AddHandlerOnce allows you to add an event handler that will be fired the next time
  98. // the Discord WSAPI event that matches the function fires.
  99. // See AddHandler for more details.
  100. func (s *Session) AddHandlerOnce(handler interface{}) func() {
  101. eh := handlerForInterface(handler)
  102. if eh == nil {
  103. s.log(LogError, "Invalid handler type, handler will never be called")
  104. return func() {}
  105. }
  106. return s.addEventHandlerOnce(eh)
  107. }
  108. // removeEventHandler instance removes an event handler instance.
  109. func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance) {
  110. s.handlersMu.Lock()
  111. defer s.handlersMu.Unlock()
  112. handlers := s.handlers[t]
  113. for i := range handlers {
  114. if handlers[i] == ehi {
  115. s.handlers[t] = append(handlers[:i], handlers[i+1:]...)
  116. }
  117. }
  118. onceHandlers := s.onceHandlers[t]
  119. for i := range onceHandlers {
  120. if onceHandlers[i] == ehi {
  121. s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
  122. }
  123. }
  124. }
  125. // Handles calling permanent and once handlers for an event type.
  126. func (s *Session) handle(t string, i interface{}) {
  127. for _, eh := range s.handlers[t] {
  128. go eh.eventHandler.Handle(s, i)
  129. }
  130. if len(s.onceHandlers[t]) > 0 {
  131. for _, eh := range s.onceHandlers[t] {
  132. go eh.eventHandler.Handle(s, i)
  133. }
  134. s.onceHandlers[t] = nil
  135. }
  136. }
  137. // Handles an event type by calling internal methods, firing handlers and firing the
  138. // interface{} event.
  139. func (s *Session) handleEvent(t string, i interface{}) {
  140. s.handlersMu.RLock()
  141. defer s.handlersMu.RUnlock()
  142. // All events are dispatched internally first.
  143. s.onInterface(i)
  144. // Then they are dispatched to anyone handling interface{} events.
  145. s.handle(interfaceEventType, i)
  146. // Finally they are dispatched to any typed handlers.
  147. s.handle(t, i)
  148. }
  149. // setGuildIds will set the GuildID on all the members of a guild.
  150. // This is done as event data does not have it set.
  151. func setGuildIds(g *Guild) {
  152. for _, c := range g.Channels {
  153. c.GuildID = g.ID
  154. }
  155. for _, m := range g.Members {
  156. m.GuildID = g.ID
  157. }
  158. for _, vs := range g.VoiceStates {
  159. vs.GuildID = g.ID
  160. }
  161. }
  162. // onInterface handles all internal events and routes them to the appropriate internal handler.
  163. func (s *Session) onInterface(i interface{}) {
  164. switch t := i.(type) {
  165. case *Ready:
  166. for _, g := range t.Guilds {
  167. setGuildIds(g)
  168. }
  169. s.onReady(t)
  170. case *GuildCreate:
  171. setGuildIds(t.Guild)
  172. case *GuildUpdate:
  173. setGuildIds(t.Guild)
  174. case *Resumed:
  175. s.onResumed(t)
  176. case *VoiceServerUpdate:
  177. go s.onVoiceServerUpdate(t)
  178. case *VoiceStateUpdate:
  179. go s.onVoiceStateUpdate(t)
  180. }
  181. s.State.onInterface(s, i)
  182. }
  183. // onReady handles the ready event.
  184. func (s *Session) onReady(r *Ready) {
  185. // Store the SessionID within the Session struct.
  186. s.sessionID = r.SessionID
  187. // Start the heartbeat to keep the connection alive.
  188. go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
  189. }
  190. // onResumed handles the resumed event.
  191. func (s *Session) onResumed(r *Resumed) {
  192. // Start the heartbeat to keep the connection alive.
  193. go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
  194. }