commit
290e3c6b87
5 changed files with 136 additions and 60 deletions
71
discord.go
71
discord.go
|
@ -122,11 +122,11 @@ func New(args ...interface{}) (s *Session, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// AddHandler allows you to add an event handler that will be fired anytime
|
||||
// the given event is triggered.
|
||||
func (s *Session) AddHandler(handler interface{}) {
|
||||
s.initialize()
|
||||
|
||||
// validateHandler takes an event handler func, and returns the type of event.
|
||||
// eg.
|
||||
// Session.validateHandler(func (s *discordgo.Session, m *discordgo.MessageCreate))
|
||||
// will return the reflect.Type of *discordgo.MessageCreate
|
||||
func (s *Session) validateHandler(handler interface{}) reflect.Type {
|
||||
handlerType := reflect.TypeOf(handler)
|
||||
|
||||
if handlerType.NumIn() != 2 {
|
||||
|
@ -137,9 +137,6 @@ func (s *Session) AddHandler(handler interface{}) {
|
|||
panic("Unable to add event handler, first argument must be of type *discordgo.Session.")
|
||||
}
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
eventType := handlerType.In(1)
|
||||
|
||||
// Support handlers of type interface{}, this is a special handler, which is triggered on every event.
|
||||
|
@ -147,18 +144,62 @@ func (s *Session) AddHandler(handler interface{}) {
|
|||
eventType = nil
|
||||
}
|
||||
|
||||
return eventType
|
||||
}
|
||||
|
||||
// AddHandler allows you to add an event handler that will be fired anytime
|
||||
// the Discord WSAPI event that matches the interface fires.
|
||||
// eventToInterface in events.go has a list of all the Discord WSAPI events
|
||||
// and their respective interface.
|
||||
// eg:
|
||||
// Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
// })
|
||||
//
|
||||
// or:
|
||||
// Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
|
||||
// })
|
||||
// The return value of this method is a function, that when called will remove the
|
||||
// event handler.
|
||||
func (s *Session) AddHandler(handler interface{}) func() {
|
||||
s.initialize()
|
||||
|
||||
eventType := s.validateHandler(handler)
|
||||
|
||||
s.handlersMu.Lock()
|
||||
defer s.handlersMu.Unlock()
|
||||
|
||||
h := reflect.ValueOf(handler)
|
||||
|
||||
handlers := s.handlers[eventType]
|
||||
if handlers == nil {
|
||||
handlers = []reflect.Value{}
|
||||
}
|
||||
s.handlers[eventType] = append(handlers, reflect.ValueOf(handler))
|
||||
s.handlers[eventType] = append(handlers, h)
|
||||
|
||||
// This must be done as we need a consistent reference to the
|
||||
// reflected value, otherwise a RemoveHandler method would have
|
||||
// been nice.
|
||||
return func() {
|
||||
s.handlersMu.Lock()
|
||||
defer s.handlersMu.Unlock()
|
||||
|
||||
handlers := s.handlers[eventType]
|
||||
for i, v := range handlers {
|
||||
if h == v {
|
||||
s.handlers[eventType] = append(handlers[:i], handlers[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle calls any handlers that match the event type and any handlers of
|
||||
// interface{}.
|
||||
func (s *Session) handle(event interface{}) {
|
||||
s.initialize()
|
||||
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
s.handlersMu.RLock()
|
||||
defer s.handlersMu.RUnlock()
|
||||
|
||||
handlerParameters := []reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}
|
||||
|
||||
|
@ -177,16 +218,14 @@ func (s *Session) handle(event interface{}) {
|
|||
|
||||
// initialize adds all internal handlers and state tracking handlers.
|
||||
func (s *Session) initialize() {
|
||||
s.RLock()
|
||||
s.handlersMu.Lock()
|
||||
if s.handlers != nil {
|
||||
s.RUnlock()
|
||||
s.handlersMu.Unlock()
|
||||
return
|
||||
}
|
||||
s.RUnlock()
|
||||
|
||||
s.Lock()
|
||||
s.handlers = map[interface{}][]reflect.Value{}
|
||||
s.Unlock()
|
||||
s.handlersMu.Unlock()
|
||||
|
||||
s.AddHandler(s.onEvent)
|
||||
s.AddHandler(s.onReady)
|
||||
|
|
|
@ -225,15 +225,15 @@ func TestOpenClose(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestHandlers(t *testing.T) {
|
||||
testHandlerCalled := false
|
||||
testHandler := func(s *Session, t *testing.T) {
|
||||
testHandlerCalled = true
|
||||
func TestAddHandler(t *testing.T) {
|
||||
testHandlerCalled := 0
|
||||
testHandler := func(s *Session, m *MessageCreate) {
|
||||
testHandlerCalled++
|
||||
}
|
||||
|
||||
interfaceHandlerCalled := false
|
||||
interfaceHandlerCalled := 0
|
||||
interfaceHandler := func(s *Session, i interface{}) {
|
||||
interfaceHandlerCalled = true
|
||||
interfaceHandlerCalled++
|
||||
}
|
||||
|
||||
bogusHandlerCalled := false
|
||||
|
@ -243,20 +243,46 @@ func TestHandlers(t *testing.T) {
|
|||
|
||||
d := Session{}
|
||||
d.AddHandler(testHandler)
|
||||
d.AddHandler(testHandler)
|
||||
|
||||
d.AddHandler(interfaceHandler)
|
||||
d.AddHandler(bogusHandler)
|
||||
|
||||
d.handle(t)
|
||||
d.handle(&MessageCreate{})
|
||||
d.handle(&MessageDelete{})
|
||||
|
||||
if !testHandlerCalled {
|
||||
t.Fatalf("testHandler was not called.")
|
||||
// testHandler will be called twice because it was added twice.
|
||||
if testHandlerCalled != 2 {
|
||||
t.Fatalf("testHandler was not called twice.")
|
||||
}
|
||||
|
||||
if !interfaceHandlerCalled {
|
||||
t.Fatalf("interfaceHandler was not called.")
|
||||
// interfaceHandler will be called twice, once for each event.
|
||||
if interfaceHandlerCalled != 2 {
|
||||
t.Fatalf("interfaceHandler was not called twice.")
|
||||
}
|
||||
|
||||
if bogusHandlerCalled {
|
||||
t.Fatalf("bogusHandler was called.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveHandler(t *testing.T) {
|
||||
testHandlerCalled := 0
|
||||
testHandler := func(s *Session, m *MessageCreate) {
|
||||
testHandlerCalled++
|
||||
}
|
||||
|
||||
d := Session{}
|
||||
r := d.AddHandler(testHandler)
|
||||
|
||||
d.handle(&MessageCreate{})
|
||||
|
||||
r()
|
||||
|
||||
d.handle(&MessageCreate{})
|
||||
|
||||
// testHandler will be called once, as it was removed in between calls.
|
||||
if testHandlerCalled != 1 {
|
||||
t.Fatalf("testHandler was not called once.")
|
||||
}
|
||||
}
|
||||
|
|
42
events.go
42
events.go
|
@ -1,5 +1,47 @@
|
|||
package discordgo
|
||||
|
||||
// eventToInterface is a mapping of Discord WSAPI events to their
|
||||
// DiscordGo event container.
|
||||
// Each Discord WSAPI event maps to a unique interface.
|
||||
// Use Session.AddHandler with one of these types to handle that
|
||||
// type of event.
|
||||
// eg:
|
||||
// Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
// })
|
||||
//
|
||||
// or:
|
||||
// Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
|
||||
// })
|
||||
var eventToInterface = map[string]interface{}{
|
||||
"CHANNEL_CREATE": ChannelCreate{},
|
||||
"CHANNEL_UPDATE": ChannelUpdate{},
|
||||
"CHANNEL_DELETE": ChannelDelete{},
|
||||
"GUILD_CREATE": GuildCreate{},
|
||||
"GUILD_UPDATE": GuildUpdate{},
|
||||
"GUILD_DELETE": GuildDelete{},
|
||||
"GUILD_BAN_ADD": GuildBanAdd{},
|
||||
"GUILD_BAN_REMOVE": GuildBanRemove{},
|
||||
"GUILD_MEMBER_ADD": GuildMemberAdd{},
|
||||
"GUILD_MEMBER_UPDATE": GuildMemberUpdate{},
|
||||
"GUILD_MEMBER_REMOVE": GuildMemberRemove{},
|
||||
"GUILD_ROLE_CREATE": GuildRoleCreate{},
|
||||
"GUILD_ROLE_UPDATE": GuildRoleUpdate{},
|
||||
"GUILD_ROLE_DELETE": GuildRoleDelete{},
|
||||
"GUILD_INTEGRATIONS_UPDATE": GuildIntegrationsUpdate{},
|
||||
"GUILD_EMOJIS_UPDATE": GuildEmojisUpdate{},
|
||||
"MESSAGE_ACK": MessageAck{},
|
||||
"MESSAGE_CREATE": MessageCreate{},
|
||||
"MESSAGE_UPDATE": MessageUpdate{},
|
||||
"MESSAGE_DELETE": MessageDelete{},
|
||||
"PRESENCE_UPDATE": PresenceUpdate{},
|
||||
"READY": Ready{},
|
||||
"USER_UPDATE": UserUpdate{},
|
||||
"USER_SETTINGS_UPDATE": UserSettingsUpdate{},
|
||||
"TYPING_START": TypingStart{},
|
||||
"VOICE_SERVER_UPDATE": VoiceServerUpdate{},
|
||||
"VOICE_STATE_UPDATE": VoiceStateUpdate{},
|
||||
}
|
||||
|
||||
// Connect is an empty struct for an event.
|
||||
type Connect struct{}
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ type Session struct {
|
|||
// StateEnabled is true.
|
||||
State *State
|
||||
|
||||
// This is a mapping of event structs to a reflected value
|
||||
handlersMu sync.RWMutex
|
||||
// This is a mapping of event struct to a reflected value
|
||||
// for event handlers.
|
||||
// We store the reflected value instead of the function
|
||||
// reference as it is more performant, instead of re-reflecting
|
||||
|
|
32
wsapi.go
32
wsapi.go
|
@ -245,38 +245,6 @@ func (s *Session) UpdateStatus(idle int, game string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// eventToInterface is a mapping of Discord WSAPI events to their
|
||||
// DiscordGo event container.
|
||||
var eventToInterface = map[string]interface{}{
|
||||
"CHANNEL_CREATE": ChannelCreate{},
|
||||
"CHANNEL_UPDATE": ChannelUpdate{},
|
||||
"CHANNEL_DELETE": ChannelDelete{},
|
||||
"GUILD_CREATE": GuildCreate{},
|
||||
"GUILD_UPDATE": GuildUpdate{},
|
||||
"GUILD_DELETE": GuildDelete{},
|
||||
"GUILD_BAN_ADD": GuildBanAdd{},
|
||||
"GUILD_BAN_REMOVE": GuildBanRemove{},
|
||||
"GUILD_MEMBER_ADD": GuildMemberAdd{},
|
||||
"GUILD_MEMBER_UPDATE": GuildMemberUpdate{},
|
||||
"GUILD_MEMBER_REMOVE": GuildMemberRemove{},
|
||||
"GUILD_ROLE_CREATE": GuildRoleCreate{},
|
||||
"GUILD_ROLE_UPDATE": GuildRoleUpdate{},
|
||||
"GUILD_ROLE_DELETE": GuildRoleDelete{},
|
||||
"GUILD_INTEGRATIONS_UPDATE": GuildIntegrationsUpdate{},
|
||||
"GUILD_EMOJIS_UPDATE": GuildEmojisUpdate{},
|
||||
"MESSAGE_ACK": MessageAck{},
|
||||
"MESSAGE_CREATE": MessageCreate{},
|
||||
"MESSAGE_UPDATE": MessageUpdate{},
|
||||
"MESSAGE_DELETE": MessageDelete{},
|
||||
"PRESENCE_UPDATE": PresenceUpdate{},
|
||||
"READY": Ready{},
|
||||
"USER_UPDATE": UserUpdate{},
|
||||
"USER_SETTINGS_UPDATE": UserSettingsUpdate{},
|
||||
"TYPING_START": TypingStart{},
|
||||
"VOICE_SERVER_UPDATE": VoiceServerUpdate{},
|
||||
"VOICE_STATE_UPDATE": VoiceStateUpdate{},
|
||||
}
|
||||
|
||||
// Front line handler for all Websocket Events. Determines the
|
||||
// event type and passes the message along to the next handler.
|
||||
|
||||
|
|
Loading…
Reference in a new issue