Browse Source

Remove use of reflect.

This introduces gogenerate'ed EventHandlers from the files in events.go

This also adds support for AddHandlerOnce.
Chris Rhodes 8 years ago
parent
commit
36601253a4
9 changed files with 1505 additions and 389 deletions
  1. 1 171
      discord.go
  2. 4 4
      discord_test.go
  3. 238 0
      event.go
  4. 977 0
      eventhandlers.go
  5. 147 96
      events.go
  6. 1 1
      restapi.go
  7. 5 91
      structs.go
  8. 123 0
      tools/cmd/eventhandlers/main.go
  9. 9 26
      wsapi.go

+ 1 - 171
discord.go

@@ -13,10 +13,7 @@
 // Package discordgo provides Discord binding for Go
 package discordgo
 
-import (
-	"fmt"
-	"reflect"
-)
+import "fmt"
 
 // VERSION of Discordgo, follows Symantic Versioning. (http://semver.org/)
 const VERSION = "0.14.0-dev"
@@ -126,170 +123,3 @@ func New(args ...interface{}) (s *Session, err error) {
 
 	return
 }
-
-// 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 {
-		panic("Unable to add event handler, handler must be of the type func(*discordgo.Session, *discordgo.EventType).")
-	}
-
-	if handlerType.In(0) != reflect.TypeOf(s) {
-		panic("Unable to add event handler, first argument must be of type *discordgo.Session.")
-	}
-
-	eventType := handlerType.In(1)
-
-	// Support handlers of type interface{}, this is a special handler, which is triggered on every event.
-	if eventType.Kind() == reflect.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)
-
-	s.handlers[eventType] = append(s.handlers[eventType], 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.handlersMu.RLock()
-	defer s.handlersMu.RUnlock()
-
-	if s.handlers == nil {
-		return
-	}
-
-	handlerParameters := []reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}
-
-	s.onInterface(event)
-
-	if handlers, ok := s.handlers[nil]; ok {
-		for _, handler := range handlers {
-			go handler.Call(handlerParameters)
-		}
-	}
-
-	if handlers, ok := s.handlers[reflect.TypeOf(event)]; ok {
-		for _, handler := range handlers {
-			go handler.Call(handlerParameters)
-		}
-	}
-}
-
-// initialize adds all internal handlers and state tracking handlers.
-func (s *Session) initialize() {
-
-	s.log(LogInformational, "called")
-
-	s.handlersMu.Lock()
-	defer s.handlersMu.Unlock()
-
-	if s.handlers != nil {
-		return
-	}
-
-	s.handlers = map[interface{}][]reflect.Value{}
-}
-
-// setGuildIds will set the GuildID on all the members of a guild.
-// This is done as event data does not have it set.
-func setGuildIds(g *Guild) {
-	for _, c := range g.Channels {
-		c.GuildID = g.ID
-	}
-
-	for _, m := range g.Members {
-		m.GuildID = g.ID
-	}
-
-	for _, vs := range g.VoiceStates {
-		vs.GuildID = g.ID
-	}
-}
-
-// onInterface handles all internal events and routes them to the appropriate internal handler.
-func (s *Session) onInterface(i interface{}) {
-	switch t := i.(type) {
-	case *Ready:
-		for _, g := range t.Guilds {
-			setGuildIds(g)
-		}
-		s.onReady(t)
-	case *GuildCreate:
-		setGuildIds(t.Guild)
-	case *GuildUpdate:
-		setGuildIds(t.Guild)
-	case *Resumed:
-		s.onResumed(t)
-	case *VoiceServerUpdate:
-		go s.onVoiceServerUpdate(t)
-	case *VoiceStateUpdate:
-		go s.onVoiceStateUpdate(t)
-	}
-	s.State.onInterface(s, i)
-}
-
-// onReady handles the ready event.
-func (s *Session) onReady(r *Ready) {
-
-	// Store the SessionID within the Session struct.
-	s.sessionID = r.SessionID
-
-	// Start the heartbeat to keep the connection alive.
-	go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
-}
-
-// onResumed handles the resumed event.
-func (s *Session) onResumed(r *Resumed) {
-
-	// Start the heartbeat to keep the connection alive.
-	go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
-}

+ 4 - 4
discord_test.go

@@ -223,8 +223,8 @@ func TestAddHandler(t *testing.T) {
 	d.AddHandler(interfaceHandler)
 	d.AddHandler(bogusHandler)
 
-	d.handle(&MessageCreate{})
-	d.handle(&MessageDelete{})
+	d.handleEvent(messageCreateEventType, &MessageCreate{})
+	d.handleEvent(messageDeleteEventType, &MessageDelete{})
 
 	<-time.After(500 * time.Millisecond)
 
@@ -253,11 +253,11 @@ func TestRemoveHandler(t *testing.T) {
 	d := Session{}
 	r := d.AddHandler(testHandler)
 
-	d.handle(&MessageCreate{})
+	d.handleEvent(messageCreateEventType, &MessageCreate{})
 
 	r()
 
-	d.handle(&MessageCreate{})
+	d.handleEvent(messageCreateEventType, &MessageCreate{})
 
 	<-time.After(500 * time.Millisecond)
 

+ 238 - 0
event.go

@@ -0,0 +1,238 @@
+package discordgo
+
+import "fmt"
+
+// EventHandler is an interface for Discord events.
+type EventHandler interface {
+	// Type returns the type of event this handler belongs to.
+	Type() string
+
+	// Handle is called whenever an event of Type() happens.
+	// It is the recievers responsibility to type assert that the interface
+	// is the expected struct.
+	Handle(*Session, interface{})
+}
+
+// EventInterfaceProvider is an interface for providing empty interfaces for
+// Discord events.
+type EventInterfaceProvider interface {
+	// Type is the type of event this handler belongs to.
+	Type() string
+
+	// New returns a new instance of the struct this event handler handles.
+	// This is called once per event.
+	// The struct is provided to all handlers of the same Type().
+	New() interface{}
+}
+
+// interfaceEventType is the event handler type for interface{} events.
+const interfaceEventType = "__INTERFACE__"
+
+// interfaceEventHandler is an event handler for interface{} events.
+type interfaceEventHandler func(*Session, interface{})
+
+// Type returns the event type for interface{} events.
+func (eh interfaceEventHandler) Type() string {
+	return interfaceEventType
+}
+
+// Handle is the handler for an interface{} event.
+func (eh interfaceEventHandler) Handle(s *Session, i interface{}) {
+	eh(s, i)
+}
+
+var registeredInterfaceProviders = map[string]EventInterfaceProvider{}
+
+// registerInterfaceProvider registers a provider so that DiscordGo can
+// access it's New() method.
+func registerInterfaceProvider(eh EventInterfaceProvider) error {
+	if _, ok := registeredInterfaceProviders[eh.Type()]; ok {
+		return fmt.Errorf("event %s already registered", eh.Type())
+	}
+	registeredInterfaceProviders[eh.Type()] = eh
+	return nil
+}
+
+// eventHandlerInstance is a wrapper around an event handler, as functions
+// cannot be compared directly.
+type eventHandlerInstance struct {
+	eventHandler EventHandler
+}
+
+// addEventHandler adds an event handler that will be fired anytime
+// the Discord WSAPI matching eventHandler.Type() fires.
+func (s *Session) addEventHandler(eventHandler EventHandler) func() {
+	s.handlersMu.Lock()
+	defer s.handlersMu.Unlock()
+
+	if s.handlers == nil {
+		s.handlers = map[string][]*eventHandlerInstance{}
+	}
+
+	ehi := &eventHandlerInstance{eventHandler}
+	s.handlers[eventHandler.Type()] = append(s.handlers[eventHandler.Type()], ehi)
+
+	return func() {
+		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
+	}
+}
+
+// addEventHandler adds an event handler that will be fired the next time
+// the Discord WSAPI matching eventHandler.Type() fires.
+func (s *Session) addEventHandlerOnce(eventHandler EventHandler) func() {
+	s.handlersMu.Lock()
+	defer s.handlersMu.Unlock()
+
+	if s.onceHandlers == nil {
+		s.onceHandlers = map[string][]*eventHandlerInstance{}
+	}
+
+	ehi := &eventHandlerInstance{eventHandler}
+	s.onceHandlers[eventHandler.Type()] = append(s.onceHandlers[eventHandler.Type()], ehi)
+
+	return func() {
+		s.removeEventHandlerInstance(eventHandler.Type(), ehi)
+	}
+}
+
+// AddHandler allows you to add an event handler that will be fired anytime
+// the Discord WSAPI event that matches the function fires.
+// events.go contains all the Discord WSAPI events that can be fired.
+// 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() {
+	eh := handlerForInterface(handler)
+
+	if eh == nil {
+		s.log(LogError, "Invalid handler type, handler will never be called")
+		return func() {}
+	}
+
+	return s.addEventHandler(eh)
+}
+
+// AddHandlerOnce allows you to add an event handler that will be fired the next time
+// the Discord WSAPI event that matches the function fires.
+// See AddHandler for more details.
+func (s *Session) AddHandlerOnce(handler interface{}) func() {
+	eh := handlerForInterface(handler)
+
+	if eh == nil {
+		s.log(LogError, "Invalid handler type, handler will never be called")
+		return func() {}
+	}
+
+	return s.addEventHandlerOnce(eh)
+}
+
+// removeEventHandler instance removes an event handler instance.
+func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance) {
+	s.handlersMu.Lock()
+	defer s.handlersMu.Unlock()
+
+	handlers := s.handlers[t]
+	for i := range handlers {
+		if handlers[i] == ehi {
+			s.handlers[t] = append(handlers[:i], handlers[i+1:]...)
+		}
+	}
+
+	onceHandlers := s.onceHandlers[t]
+	for i := range onceHandlers {
+		if onceHandlers[i] == ehi {
+			s.onceHandlers[t] = append(onceHandlers[:i], handlers[i+1:]...)
+		}
+	}
+}
+
+// Handles calling permanent and once handlers for an event type.
+func (s *Session) handle(t string, i interface{}) {
+	for _, eh := range s.handlers[t] {
+		go eh.eventHandler.Handle(s, i)
+	}
+
+	if len(s.onceHandlers[t]) > 0 {
+		for _, eh := range s.onceHandlers[t] {
+			go eh.eventHandler.Handle(s, i)
+		}
+		s.onceHandlers[t] = nil
+	}
+}
+
+// Handles an event type by calling internal methods, firing handlers and firing the
+// interface{} event.
+func (s *Session) handleEvent(t string, i interface{}) {
+	s.handlersMu.RLock()
+	defer s.handlersMu.RUnlock()
+
+	// All events are dispatched internally first.
+	s.onInterface(i)
+
+	// Then they are dispatched to anyone handling interface{} events.
+	s.handle(interfaceEventType, i)
+
+	// Finally they are dispatched to any typed handlers.
+	s.handle(t, i)
+}
+
+// setGuildIds will set the GuildID on all the members of a guild.
+// This is done as event data does not have it set.
+func setGuildIds(g *Guild) {
+	for _, c := range g.Channels {
+		c.GuildID = g.ID
+	}
+
+	for _, m := range g.Members {
+		m.GuildID = g.ID
+	}
+
+	for _, vs := range g.VoiceStates {
+		vs.GuildID = g.ID
+	}
+}
+
+// onInterface handles all internal events and routes them to the appropriate internal handler.
+func (s *Session) onInterface(i interface{}) {
+	switch t := i.(type) {
+	case *Ready:
+		for _, g := range t.Guilds {
+			setGuildIds(g)
+		}
+		s.onReady(t)
+	case *GuildCreate:
+		setGuildIds(t.Guild)
+	case *GuildUpdate:
+		setGuildIds(t.Guild)
+	case *Resumed:
+		s.onResumed(t)
+	case *VoiceServerUpdate:
+		go s.onVoiceServerUpdate(t)
+	case *VoiceStateUpdate:
+		go s.onVoiceStateUpdate(t)
+	}
+	s.State.onInterface(s, i)
+}
+
+// onReady handles the ready event.
+func (s *Session) onReady(r *Ready) {
+
+	// Store the SessionID within the Session struct.
+	s.sessionID = r.SessionID
+
+	// Start the heartbeat to keep the connection alive.
+	go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
+}
+
+// onResumed handles the resumed event.
+func (s *Session) onResumed(r *Resumed) {
+
+	// Start the heartbeat to keep the connection alive.
+	go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
+}

+ 977 - 0
eventhandlers.go

@@ -0,0 +1,977 @@
+// Code generated by \"eventhandlers\"; DO NOT EDIT
+// See events.go
+
+package discordgo
+
+// Following are all the event types.
+// Event type values are used to match the events returned by Discord.
+// EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
+const (
+	channelCreateEventType           = "CHANNEL_CREATE"
+	channelDeleteEventType           = "CHANNEL_DELETE"
+	channelPinsUpdateEventType       = "CHANNEL_PINS_UPDATE"
+	channelUpdateEventType           = "CHANNEL_UPDATE"
+	connectEventType                 = "__CONNECT__"
+	disconnectEventType              = "__DISCONNECT__"
+	eventEventType                   = "__EVENT__"
+	guildBanAddEventType             = "GUILD_BAN_ADD"
+	guildBanRemoveEventType          = "GUILD_BAN_REMOVE"
+	guildCreateEventType             = "GUILD_CREATE"
+	guildDeleteEventType             = "GUILD_DELETE"
+	guildEmojisUpdateEventType       = "GUILD_EMOJIS_UPDATE"
+	guildIntegrationsUpdateEventType = "GUILD_INTEGRATIONS_UPDATE"
+	guildMemberAddEventType          = "GUILD_MEMBER_ADD"
+	guildMemberRemoveEventType       = "GUILD_MEMBER_REMOVE"
+	guildMemberUpdateEventType       = "GUILD_MEMBER_UPDATE"
+	guildMembersChunkEventType       = "GUILD_MEMBERS_CHUNK"
+	guildRoleCreateEventType         = "GUILD_ROLE_CREATE"
+	guildRoleDeleteEventType         = "GUILD_ROLE_DELETE"
+	guildRoleUpdateEventType         = "GUILD_ROLE_UPDATE"
+	guildUpdateEventType             = "GUILD_UPDATE"
+	messageAckEventType              = "MESSAGE_ACK"
+	messageCreateEventType           = "MESSAGE_CREATE"
+	messageDeleteEventType           = "MESSAGE_DELETE"
+	messageReactionAddEventType      = "MESSAGE_REACTION_ADD"
+	messageReactionRemoveEventType   = "MESSAGE_REACTION_REMOVE"
+	messageUpdateEventType           = "MESSAGE_UPDATE"
+	presenceUpdateEventType          = "PRESENCE_UPDATE"
+	presencesReplaceEventType        = "PRESENCES_REPLACE"
+	rateLimitEventType               = "__RATE_LIMIT__"
+	readyEventType                   = "READY"
+	relationshipAddEventType         = "RELATIONSHIP_ADD"
+	relationshipRemoveEventType      = "RELATIONSHIP_REMOVE"
+	resumedEventType                 = "RESUMED"
+	typingStartEventType             = "TYPING_START"
+	userGuildSettingsUpdateEventType = "USER_GUILD_SETTINGS_UPDATE"
+	userSettingsUpdateEventType      = "USER_SETTINGS_UPDATE"
+	userUpdateEventType              = "USER_UPDATE"
+	voiceServerUpdateEventType       = "VOICE_SERVER_UPDATE"
+	voiceStateUpdateEventType        = "VOICE_STATE_UPDATE"
+)
+
+// channelCreateEventHandler is an event handler for ChannelCreate events.
+type channelCreateEventHandler func(*Session, *ChannelCreate)
+
+// Type returns the event type for ChannelCreate events.
+func (eh channelCreateEventHandler) Type() string {
+	return channelCreateEventType
+}
+
+// New returns a new instance of ChannelCreate.
+func (eh channelCreateEventHandler) New() interface{} {
+	return &ChannelCreate{}
+}
+
+// Handle is the handler for ChannelCreate events.
+func (eh channelCreateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*ChannelCreate); ok {
+		eh(s, t)
+	}
+}
+
+// channelDeleteEventHandler is an event handler for ChannelDelete events.
+type channelDeleteEventHandler func(*Session, *ChannelDelete)
+
+// Type returns the event type for ChannelDelete events.
+func (eh channelDeleteEventHandler) Type() string {
+	return channelDeleteEventType
+}
+
+// New returns a new instance of ChannelDelete.
+func (eh channelDeleteEventHandler) New() interface{} {
+	return &ChannelDelete{}
+}
+
+// Handle is the handler for ChannelDelete events.
+func (eh channelDeleteEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*ChannelDelete); ok {
+		eh(s, t)
+	}
+}
+
+// channelPinsUpdateEventHandler is an event handler for ChannelPinsUpdate events.
+type channelPinsUpdateEventHandler func(*Session, *ChannelPinsUpdate)
+
+// Type returns the event type for ChannelPinsUpdate events.
+func (eh channelPinsUpdateEventHandler) Type() string {
+	return channelPinsUpdateEventType
+}
+
+// New returns a new instance of ChannelPinsUpdate.
+func (eh channelPinsUpdateEventHandler) New() interface{} {
+	return &ChannelPinsUpdate{}
+}
+
+// Handle is the handler for ChannelPinsUpdate events.
+func (eh channelPinsUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*ChannelPinsUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// channelUpdateEventHandler is an event handler for ChannelUpdate events.
+type channelUpdateEventHandler func(*Session, *ChannelUpdate)
+
+// Type returns the event type for ChannelUpdate events.
+func (eh channelUpdateEventHandler) Type() string {
+	return channelUpdateEventType
+}
+
+// New returns a new instance of ChannelUpdate.
+func (eh channelUpdateEventHandler) New() interface{} {
+	return &ChannelUpdate{}
+}
+
+// Handle is the handler for ChannelUpdate events.
+func (eh channelUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*ChannelUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// connectEventHandler is an event handler for Connect events.
+type connectEventHandler func(*Session, *Connect)
+
+// Type returns the event type for Connect events.
+func (eh connectEventHandler) Type() string {
+	return connectEventType
+}
+
+// New returns a new instance of Connect.
+func (eh connectEventHandler) New() interface{} {
+	return &Connect{}
+}
+
+// Handle is the handler for Connect events.
+func (eh connectEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*Connect); ok {
+		eh(s, t)
+	}
+}
+
+// disconnectEventHandler is an event handler for Disconnect events.
+type disconnectEventHandler func(*Session, *Disconnect)
+
+// Type returns the event type for Disconnect events.
+func (eh disconnectEventHandler) Type() string {
+	return disconnectEventType
+}
+
+// New returns a new instance of Disconnect.
+func (eh disconnectEventHandler) New() interface{} {
+	return &Disconnect{}
+}
+
+// Handle is the handler for Disconnect events.
+func (eh disconnectEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*Disconnect); ok {
+		eh(s, t)
+	}
+}
+
+// eventEventHandler is an event handler for Event events.
+type eventEventHandler func(*Session, *Event)
+
+// Type returns the event type for Event events.
+func (eh eventEventHandler) Type() string {
+	return eventEventType
+}
+
+// New returns a new instance of Event.
+func (eh eventEventHandler) New() interface{} {
+	return &Event{}
+}
+
+// Handle is the handler for Event events.
+func (eh eventEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*Event); ok {
+		eh(s, t)
+	}
+}
+
+// guildBanAddEventHandler is an event handler for GuildBanAdd events.
+type guildBanAddEventHandler func(*Session, *GuildBanAdd)
+
+// Type returns the event type for GuildBanAdd events.
+func (eh guildBanAddEventHandler) Type() string {
+	return guildBanAddEventType
+}
+
+// New returns a new instance of GuildBanAdd.
+func (eh guildBanAddEventHandler) New() interface{} {
+	return &GuildBanAdd{}
+}
+
+// Handle is the handler for GuildBanAdd events.
+func (eh guildBanAddEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildBanAdd); ok {
+		eh(s, t)
+	}
+}
+
+// guildBanRemoveEventHandler is an event handler for GuildBanRemove events.
+type guildBanRemoveEventHandler func(*Session, *GuildBanRemove)
+
+// Type returns the event type for GuildBanRemove events.
+func (eh guildBanRemoveEventHandler) Type() string {
+	return guildBanRemoveEventType
+}
+
+// New returns a new instance of GuildBanRemove.
+func (eh guildBanRemoveEventHandler) New() interface{} {
+	return &GuildBanRemove{}
+}
+
+// Handle is the handler for GuildBanRemove events.
+func (eh guildBanRemoveEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildBanRemove); ok {
+		eh(s, t)
+	}
+}
+
+// guildCreateEventHandler is an event handler for GuildCreate events.
+type guildCreateEventHandler func(*Session, *GuildCreate)
+
+// Type returns the event type for GuildCreate events.
+func (eh guildCreateEventHandler) Type() string {
+	return guildCreateEventType
+}
+
+// New returns a new instance of GuildCreate.
+func (eh guildCreateEventHandler) New() interface{} {
+	return &GuildCreate{}
+}
+
+// Handle is the handler for GuildCreate events.
+func (eh guildCreateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildCreate); ok {
+		eh(s, t)
+	}
+}
+
+// guildDeleteEventHandler is an event handler for GuildDelete events.
+type guildDeleteEventHandler func(*Session, *GuildDelete)
+
+// Type returns the event type for GuildDelete events.
+func (eh guildDeleteEventHandler) Type() string {
+	return guildDeleteEventType
+}
+
+// New returns a new instance of GuildDelete.
+func (eh guildDeleteEventHandler) New() interface{} {
+	return &GuildDelete{}
+}
+
+// Handle is the handler for GuildDelete events.
+func (eh guildDeleteEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildDelete); ok {
+		eh(s, t)
+	}
+}
+
+// guildEmojisUpdateEventHandler is an event handler for GuildEmojisUpdate events.
+type guildEmojisUpdateEventHandler func(*Session, *GuildEmojisUpdate)
+
+// Type returns the event type for GuildEmojisUpdate events.
+func (eh guildEmojisUpdateEventHandler) Type() string {
+	return guildEmojisUpdateEventType
+}
+
+// New returns a new instance of GuildEmojisUpdate.
+func (eh guildEmojisUpdateEventHandler) New() interface{} {
+	return &GuildEmojisUpdate{}
+}
+
+// Handle is the handler for GuildEmojisUpdate events.
+func (eh guildEmojisUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildEmojisUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// guildIntegrationsUpdateEventHandler is an event handler for GuildIntegrationsUpdate events.
+type guildIntegrationsUpdateEventHandler func(*Session, *GuildIntegrationsUpdate)
+
+// Type returns the event type for GuildIntegrationsUpdate events.
+func (eh guildIntegrationsUpdateEventHandler) Type() string {
+	return guildIntegrationsUpdateEventType
+}
+
+// New returns a new instance of GuildIntegrationsUpdate.
+func (eh guildIntegrationsUpdateEventHandler) New() interface{} {
+	return &GuildIntegrationsUpdate{}
+}
+
+// Handle is the handler for GuildIntegrationsUpdate events.
+func (eh guildIntegrationsUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildIntegrationsUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// guildMemberAddEventHandler is an event handler for GuildMemberAdd events.
+type guildMemberAddEventHandler func(*Session, *GuildMemberAdd)
+
+// Type returns the event type for GuildMemberAdd events.
+func (eh guildMemberAddEventHandler) Type() string {
+	return guildMemberAddEventType
+}
+
+// New returns a new instance of GuildMemberAdd.
+func (eh guildMemberAddEventHandler) New() interface{} {
+	return &GuildMemberAdd{}
+}
+
+// Handle is the handler for GuildMemberAdd events.
+func (eh guildMemberAddEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildMemberAdd); ok {
+		eh(s, t)
+	}
+}
+
+// guildMemberRemoveEventHandler is an event handler for GuildMemberRemove events.
+type guildMemberRemoveEventHandler func(*Session, *GuildMemberRemove)
+
+// Type returns the event type for GuildMemberRemove events.
+func (eh guildMemberRemoveEventHandler) Type() string {
+	return guildMemberRemoveEventType
+}
+
+// New returns a new instance of GuildMemberRemove.
+func (eh guildMemberRemoveEventHandler) New() interface{} {
+	return &GuildMemberRemove{}
+}
+
+// Handle is the handler for GuildMemberRemove events.
+func (eh guildMemberRemoveEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildMemberRemove); ok {
+		eh(s, t)
+	}
+}
+
+// guildMemberUpdateEventHandler is an event handler for GuildMemberUpdate events.
+type guildMemberUpdateEventHandler func(*Session, *GuildMemberUpdate)
+
+// Type returns the event type for GuildMemberUpdate events.
+func (eh guildMemberUpdateEventHandler) Type() string {
+	return guildMemberUpdateEventType
+}
+
+// New returns a new instance of GuildMemberUpdate.
+func (eh guildMemberUpdateEventHandler) New() interface{} {
+	return &GuildMemberUpdate{}
+}
+
+// Handle is the handler for GuildMemberUpdate events.
+func (eh guildMemberUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildMemberUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// guildMembersChunkEventHandler is an event handler for GuildMembersChunk events.
+type guildMembersChunkEventHandler func(*Session, *GuildMembersChunk)
+
+// Type returns the event type for GuildMembersChunk events.
+func (eh guildMembersChunkEventHandler) Type() string {
+	return guildMembersChunkEventType
+}
+
+// New returns a new instance of GuildMembersChunk.
+func (eh guildMembersChunkEventHandler) New() interface{} {
+	return &GuildMembersChunk{}
+}
+
+// Handle is the handler for GuildMembersChunk events.
+func (eh guildMembersChunkEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildMembersChunk); ok {
+		eh(s, t)
+	}
+}
+
+// guildRoleCreateEventHandler is an event handler for GuildRoleCreate events.
+type guildRoleCreateEventHandler func(*Session, *GuildRoleCreate)
+
+// Type returns the event type for GuildRoleCreate events.
+func (eh guildRoleCreateEventHandler) Type() string {
+	return guildRoleCreateEventType
+}
+
+// New returns a new instance of GuildRoleCreate.
+func (eh guildRoleCreateEventHandler) New() interface{} {
+	return &GuildRoleCreate{}
+}
+
+// Handle is the handler for GuildRoleCreate events.
+func (eh guildRoleCreateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildRoleCreate); ok {
+		eh(s, t)
+	}
+}
+
+// guildRoleDeleteEventHandler is an event handler for GuildRoleDelete events.
+type guildRoleDeleteEventHandler func(*Session, *GuildRoleDelete)
+
+// Type returns the event type for GuildRoleDelete events.
+func (eh guildRoleDeleteEventHandler) Type() string {
+	return guildRoleDeleteEventType
+}
+
+// New returns a new instance of GuildRoleDelete.
+func (eh guildRoleDeleteEventHandler) New() interface{} {
+	return &GuildRoleDelete{}
+}
+
+// Handle is the handler for GuildRoleDelete events.
+func (eh guildRoleDeleteEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildRoleDelete); ok {
+		eh(s, t)
+	}
+}
+
+// guildRoleUpdateEventHandler is an event handler for GuildRoleUpdate events.
+type guildRoleUpdateEventHandler func(*Session, *GuildRoleUpdate)
+
+// Type returns the event type for GuildRoleUpdate events.
+func (eh guildRoleUpdateEventHandler) Type() string {
+	return guildRoleUpdateEventType
+}
+
+// New returns a new instance of GuildRoleUpdate.
+func (eh guildRoleUpdateEventHandler) New() interface{} {
+	return &GuildRoleUpdate{}
+}
+
+// Handle is the handler for GuildRoleUpdate events.
+func (eh guildRoleUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildRoleUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// guildUpdateEventHandler is an event handler for GuildUpdate events.
+type guildUpdateEventHandler func(*Session, *GuildUpdate)
+
+// Type returns the event type for GuildUpdate events.
+func (eh guildUpdateEventHandler) Type() string {
+	return guildUpdateEventType
+}
+
+// New returns a new instance of GuildUpdate.
+func (eh guildUpdateEventHandler) New() interface{} {
+	return &GuildUpdate{}
+}
+
+// Handle is the handler for GuildUpdate events.
+func (eh guildUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*GuildUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// messageAckEventHandler is an event handler for MessageAck events.
+type messageAckEventHandler func(*Session, *MessageAck)
+
+// Type returns the event type for MessageAck events.
+func (eh messageAckEventHandler) Type() string {
+	return messageAckEventType
+}
+
+// New returns a new instance of MessageAck.
+func (eh messageAckEventHandler) New() interface{} {
+	return &MessageAck{}
+}
+
+// Handle is the handler for MessageAck events.
+func (eh messageAckEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*MessageAck); ok {
+		eh(s, t)
+	}
+}
+
+// messageCreateEventHandler is an event handler for MessageCreate events.
+type messageCreateEventHandler func(*Session, *MessageCreate)
+
+// Type returns the event type for MessageCreate events.
+func (eh messageCreateEventHandler) Type() string {
+	return messageCreateEventType
+}
+
+// New returns a new instance of MessageCreate.
+func (eh messageCreateEventHandler) New() interface{} {
+	return &MessageCreate{}
+}
+
+// Handle is the handler for MessageCreate events.
+func (eh messageCreateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*MessageCreate); ok {
+		eh(s, t)
+	}
+}
+
+// messageDeleteEventHandler is an event handler for MessageDelete events.
+type messageDeleteEventHandler func(*Session, *MessageDelete)
+
+// Type returns the event type for MessageDelete events.
+func (eh messageDeleteEventHandler) Type() string {
+	return messageDeleteEventType
+}
+
+// New returns a new instance of MessageDelete.
+func (eh messageDeleteEventHandler) New() interface{} {
+	return &MessageDelete{}
+}
+
+// Handle is the handler for MessageDelete events.
+func (eh messageDeleteEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*MessageDelete); ok {
+		eh(s, t)
+	}
+}
+
+// messageReactionAddEventHandler is an event handler for MessageReactionAdd events.
+type messageReactionAddEventHandler func(*Session, *MessageReactionAdd)
+
+// Type returns the event type for MessageReactionAdd events.
+func (eh messageReactionAddEventHandler) Type() string {
+	return messageReactionAddEventType
+}
+
+// New returns a new instance of MessageReactionAdd.
+func (eh messageReactionAddEventHandler) New() interface{} {
+	return &MessageReactionAdd{}
+}
+
+// Handle is the handler for MessageReactionAdd events.
+func (eh messageReactionAddEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*MessageReactionAdd); ok {
+		eh(s, t)
+	}
+}
+
+// messageReactionRemoveEventHandler is an event handler for MessageReactionRemove events.
+type messageReactionRemoveEventHandler func(*Session, *MessageReactionRemove)
+
+// Type returns the event type for MessageReactionRemove events.
+func (eh messageReactionRemoveEventHandler) Type() string {
+	return messageReactionRemoveEventType
+}
+
+// New returns a new instance of MessageReactionRemove.
+func (eh messageReactionRemoveEventHandler) New() interface{} {
+	return &MessageReactionRemove{}
+}
+
+// Handle is the handler for MessageReactionRemove events.
+func (eh messageReactionRemoveEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*MessageReactionRemove); ok {
+		eh(s, t)
+	}
+}
+
+// messageUpdateEventHandler is an event handler for MessageUpdate events.
+type messageUpdateEventHandler func(*Session, *MessageUpdate)
+
+// Type returns the event type for MessageUpdate events.
+func (eh messageUpdateEventHandler) Type() string {
+	return messageUpdateEventType
+}
+
+// New returns a new instance of MessageUpdate.
+func (eh messageUpdateEventHandler) New() interface{} {
+	return &MessageUpdate{}
+}
+
+// Handle is the handler for MessageUpdate events.
+func (eh messageUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*MessageUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// presenceUpdateEventHandler is an event handler for PresenceUpdate events.
+type presenceUpdateEventHandler func(*Session, *PresenceUpdate)
+
+// Type returns the event type for PresenceUpdate events.
+func (eh presenceUpdateEventHandler) Type() string {
+	return presenceUpdateEventType
+}
+
+// New returns a new instance of PresenceUpdate.
+func (eh presenceUpdateEventHandler) New() interface{} {
+	return &PresenceUpdate{}
+}
+
+// Handle is the handler for PresenceUpdate events.
+func (eh presenceUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*PresenceUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// presencesReplaceEventHandler is an event handler for PresencesReplace events.
+type presencesReplaceEventHandler func(*Session, *PresencesReplace)
+
+// Type returns the event type for PresencesReplace events.
+func (eh presencesReplaceEventHandler) Type() string {
+	return presencesReplaceEventType
+}
+
+// New returns a new instance of PresencesReplace.
+func (eh presencesReplaceEventHandler) New() interface{} {
+	return &PresencesReplace{}
+}
+
+// Handle is the handler for PresencesReplace events.
+func (eh presencesReplaceEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*PresencesReplace); ok {
+		eh(s, t)
+	}
+}
+
+// rateLimitEventHandler is an event handler for RateLimit events.
+type rateLimitEventHandler func(*Session, *RateLimit)
+
+// Type returns the event type for RateLimit events.
+func (eh rateLimitEventHandler) Type() string {
+	return rateLimitEventType
+}
+
+// New returns a new instance of RateLimit.
+func (eh rateLimitEventHandler) New() interface{} {
+	return &RateLimit{}
+}
+
+// Handle is the handler for RateLimit events.
+func (eh rateLimitEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*RateLimit); ok {
+		eh(s, t)
+	}
+}
+
+// readyEventHandler is an event handler for Ready events.
+type readyEventHandler func(*Session, *Ready)
+
+// Type returns the event type for Ready events.
+func (eh readyEventHandler) Type() string {
+	return readyEventType
+}
+
+// New returns a new instance of Ready.
+func (eh readyEventHandler) New() interface{} {
+	return &Ready{}
+}
+
+// Handle is the handler for Ready events.
+func (eh readyEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*Ready); ok {
+		eh(s, t)
+	}
+}
+
+// relationshipAddEventHandler is an event handler for RelationshipAdd events.
+type relationshipAddEventHandler func(*Session, *RelationshipAdd)
+
+// Type returns the event type for RelationshipAdd events.
+func (eh relationshipAddEventHandler) Type() string {
+	return relationshipAddEventType
+}
+
+// New returns a new instance of RelationshipAdd.
+func (eh relationshipAddEventHandler) New() interface{} {
+	return &RelationshipAdd{}
+}
+
+// Handle is the handler for RelationshipAdd events.
+func (eh relationshipAddEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*RelationshipAdd); ok {
+		eh(s, t)
+	}
+}
+
+// relationshipRemoveEventHandler is an event handler for RelationshipRemove events.
+type relationshipRemoveEventHandler func(*Session, *RelationshipRemove)
+
+// Type returns the event type for RelationshipRemove events.
+func (eh relationshipRemoveEventHandler) Type() string {
+	return relationshipRemoveEventType
+}
+
+// New returns a new instance of RelationshipRemove.
+func (eh relationshipRemoveEventHandler) New() interface{} {
+	return &RelationshipRemove{}
+}
+
+// Handle is the handler for RelationshipRemove events.
+func (eh relationshipRemoveEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*RelationshipRemove); ok {
+		eh(s, t)
+	}
+}
+
+// resumedEventHandler is an event handler for Resumed events.
+type resumedEventHandler func(*Session, *Resumed)
+
+// Type returns the event type for Resumed events.
+func (eh resumedEventHandler) Type() string {
+	return resumedEventType
+}
+
+// New returns a new instance of Resumed.
+func (eh resumedEventHandler) New() interface{} {
+	return &Resumed{}
+}
+
+// Handle is the handler for Resumed events.
+func (eh resumedEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*Resumed); ok {
+		eh(s, t)
+	}
+}
+
+// typingStartEventHandler is an event handler for TypingStart events.
+type typingStartEventHandler func(*Session, *TypingStart)
+
+// Type returns the event type for TypingStart events.
+func (eh typingStartEventHandler) Type() string {
+	return typingStartEventType
+}
+
+// New returns a new instance of TypingStart.
+func (eh typingStartEventHandler) New() interface{} {
+	return &TypingStart{}
+}
+
+// Handle is the handler for TypingStart events.
+func (eh typingStartEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*TypingStart); ok {
+		eh(s, t)
+	}
+}
+
+// userGuildSettingsUpdateEventHandler is an event handler for UserGuildSettingsUpdate events.
+type userGuildSettingsUpdateEventHandler func(*Session, *UserGuildSettingsUpdate)
+
+// Type returns the event type for UserGuildSettingsUpdate events.
+func (eh userGuildSettingsUpdateEventHandler) Type() string {
+	return userGuildSettingsUpdateEventType
+}
+
+// New returns a new instance of UserGuildSettingsUpdate.
+func (eh userGuildSettingsUpdateEventHandler) New() interface{} {
+	return &UserGuildSettingsUpdate{}
+}
+
+// Handle is the handler for UserGuildSettingsUpdate events.
+func (eh userGuildSettingsUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*UserGuildSettingsUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// userSettingsUpdateEventHandler is an event handler for UserSettingsUpdate events.
+type userSettingsUpdateEventHandler func(*Session, *UserSettingsUpdate)
+
+// Type returns the event type for UserSettingsUpdate events.
+func (eh userSettingsUpdateEventHandler) Type() string {
+	return userSettingsUpdateEventType
+}
+
+// New returns a new instance of UserSettingsUpdate.
+func (eh userSettingsUpdateEventHandler) New() interface{} {
+	return &UserSettingsUpdate{}
+}
+
+// Handle is the handler for UserSettingsUpdate events.
+func (eh userSettingsUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*UserSettingsUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// userUpdateEventHandler is an event handler for UserUpdate events.
+type userUpdateEventHandler func(*Session, *UserUpdate)
+
+// Type returns the event type for UserUpdate events.
+func (eh userUpdateEventHandler) Type() string {
+	return userUpdateEventType
+}
+
+// New returns a new instance of UserUpdate.
+func (eh userUpdateEventHandler) New() interface{} {
+	return &UserUpdate{}
+}
+
+// Handle is the handler for UserUpdate events.
+func (eh userUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*UserUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// voiceServerUpdateEventHandler is an event handler for VoiceServerUpdate events.
+type voiceServerUpdateEventHandler func(*Session, *VoiceServerUpdate)
+
+// Type returns the event type for VoiceServerUpdate events.
+func (eh voiceServerUpdateEventHandler) Type() string {
+	return voiceServerUpdateEventType
+}
+
+// New returns a new instance of VoiceServerUpdate.
+func (eh voiceServerUpdateEventHandler) New() interface{} {
+	return &VoiceServerUpdate{}
+}
+
+// Handle is the handler for VoiceServerUpdate events.
+func (eh voiceServerUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*VoiceServerUpdate); ok {
+		eh(s, t)
+	}
+}
+
+// voiceStateUpdateEventHandler is an event handler for VoiceStateUpdate events.
+type voiceStateUpdateEventHandler func(*Session, *VoiceStateUpdate)
+
+// Type returns the event type for VoiceStateUpdate events.
+func (eh voiceStateUpdateEventHandler) Type() string {
+	return voiceStateUpdateEventType
+}
+
+// New returns a new instance of VoiceStateUpdate.
+func (eh voiceStateUpdateEventHandler) New() interface{} {
+	return &VoiceStateUpdate{}
+}
+
+// Handle is the handler for VoiceStateUpdate events.
+func (eh voiceStateUpdateEventHandler) Handle(s *Session, i interface{}) {
+	if t, ok := i.(*VoiceStateUpdate); ok {
+		eh(s, t)
+	}
+}
+
+func handlerForInterface(handler interface{}) EventHandler {
+	switch v := handler.(type) {
+	case func(*Session, interface{}):
+		return interfaceEventHandler(v)
+	case func(*Session, *ChannelCreate):
+		return channelCreateEventHandler(v)
+	case func(*Session, *ChannelDelete):
+		return channelDeleteEventHandler(v)
+	case func(*Session, *ChannelPinsUpdate):
+		return channelPinsUpdateEventHandler(v)
+	case func(*Session, *ChannelUpdate):
+		return channelUpdateEventHandler(v)
+	case func(*Session, *Connect):
+		return connectEventHandler(v)
+	case func(*Session, *Disconnect):
+		return disconnectEventHandler(v)
+	case func(*Session, *Event):
+		return eventEventHandler(v)
+	case func(*Session, *GuildBanAdd):
+		return guildBanAddEventHandler(v)
+	case func(*Session, *GuildBanRemove):
+		return guildBanRemoveEventHandler(v)
+	case func(*Session, *GuildCreate):
+		return guildCreateEventHandler(v)
+	case func(*Session, *GuildDelete):
+		return guildDeleteEventHandler(v)
+	case func(*Session, *GuildEmojisUpdate):
+		return guildEmojisUpdateEventHandler(v)
+	case func(*Session, *GuildIntegrationsUpdate):
+		return guildIntegrationsUpdateEventHandler(v)
+	case func(*Session, *GuildMemberAdd):
+		return guildMemberAddEventHandler(v)
+	case func(*Session, *GuildMemberRemove):
+		return guildMemberRemoveEventHandler(v)
+	case func(*Session, *GuildMemberUpdate):
+		return guildMemberUpdateEventHandler(v)
+	case func(*Session, *GuildMembersChunk):
+		return guildMembersChunkEventHandler(v)
+	case func(*Session, *GuildRoleCreate):
+		return guildRoleCreateEventHandler(v)
+	case func(*Session, *GuildRoleDelete):
+		return guildRoleDeleteEventHandler(v)
+	case func(*Session, *GuildRoleUpdate):
+		return guildRoleUpdateEventHandler(v)
+	case func(*Session, *GuildUpdate):
+		return guildUpdateEventHandler(v)
+	case func(*Session, *MessageAck):
+		return messageAckEventHandler(v)
+	case func(*Session, *MessageCreate):
+		return messageCreateEventHandler(v)
+	case func(*Session, *MessageDelete):
+		return messageDeleteEventHandler(v)
+	case func(*Session, *MessageReactionAdd):
+		return messageReactionAddEventHandler(v)
+	case func(*Session, *MessageReactionRemove):
+		return messageReactionRemoveEventHandler(v)
+	case func(*Session, *MessageUpdate):
+		return messageUpdateEventHandler(v)
+	case func(*Session, *PresenceUpdate):
+		return presenceUpdateEventHandler(v)
+	case func(*Session, *PresencesReplace):
+		return presencesReplaceEventHandler(v)
+	case func(*Session, *RateLimit):
+		return rateLimitEventHandler(v)
+	case func(*Session, *Ready):
+		return readyEventHandler(v)
+	case func(*Session, *RelationshipAdd):
+		return relationshipAddEventHandler(v)
+	case func(*Session, *RelationshipRemove):
+		return relationshipRemoveEventHandler(v)
+	case func(*Session, *Resumed):
+		return resumedEventHandler(v)
+	case func(*Session, *TypingStart):
+		return typingStartEventHandler(v)
+	case func(*Session, *UserGuildSettingsUpdate):
+		return userGuildSettingsUpdateEventHandler(v)
+	case func(*Session, *UserSettingsUpdate):
+		return userSettingsUpdateEventHandler(v)
+	case func(*Session, *UserUpdate):
+		return userUpdateEventHandler(v)
+	case func(*Session, *VoiceServerUpdate):
+		return voiceServerUpdateEventHandler(v)
+	case func(*Session, *VoiceStateUpdate):
+		return voiceStateUpdateEventHandler(v)
+	}
+
+	return nil
+}
+func init() {
+	registerInterfaceProvider(channelCreateEventHandler(nil))
+	registerInterfaceProvider(channelDeleteEventHandler(nil))
+	registerInterfaceProvider(channelPinsUpdateEventHandler(nil))
+	registerInterfaceProvider(channelUpdateEventHandler(nil))
+	registerInterfaceProvider(guildBanAddEventHandler(nil))
+	registerInterfaceProvider(guildBanRemoveEventHandler(nil))
+	registerInterfaceProvider(guildCreateEventHandler(nil))
+	registerInterfaceProvider(guildDeleteEventHandler(nil))
+	registerInterfaceProvider(guildEmojisUpdateEventHandler(nil))
+	registerInterfaceProvider(guildIntegrationsUpdateEventHandler(nil))
+	registerInterfaceProvider(guildMemberAddEventHandler(nil))
+	registerInterfaceProvider(guildMemberRemoveEventHandler(nil))
+	registerInterfaceProvider(guildMemberUpdateEventHandler(nil))
+	registerInterfaceProvider(guildMembersChunkEventHandler(nil))
+	registerInterfaceProvider(guildRoleCreateEventHandler(nil))
+	registerInterfaceProvider(guildRoleDeleteEventHandler(nil))
+	registerInterfaceProvider(guildRoleUpdateEventHandler(nil))
+	registerInterfaceProvider(guildUpdateEventHandler(nil))
+	registerInterfaceProvider(messageAckEventHandler(nil))
+	registerInterfaceProvider(messageCreateEventHandler(nil))
+	registerInterfaceProvider(messageDeleteEventHandler(nil))
+	registerInterfaceProvider(messageReactionAddEventHandler(nil))
+	registerInterfaceProvider(messageReactionRemoveEventHandler(nil))
+	registerInterfaceProvider(messageUpdateEventHandler(nil))
+	registerInterfaceProvider(presenceUpdateEventHandler(nil))
+	registerInterfaceProvider(presencesReplaceEventHandler(nil))
+	registerInterfaceProvider(readyEventHandler(nil))
+	registerInterfaceProvider(relationshipAddEventHandler(nil))
+	registerInterfaceProvider(relationshipRemoveEventHandler(nil))
+	registerInterfaceProvider(resumedEventHandler(nil))
+	registerInterfaceProvider(typingStartEventHandler(nil))
+	registerInterfaceProvider(userGuildSettingsUpdateEventHandler(nil))
+	registerInterfaceProvider(userSettingsUpdateEventHandler(nil))
+	registerInterfaceProvider(userUpdateEventHandler(nil))
+	registerInterfaceProvider(voiceServerUpdateEventHandler(nil))
+	registerInterfaceProvider(voiceStateUpdateEventHandler(nil))
+}

+ 147 - 96
events.go

@@ -1,187 +1,238 @@
 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{},
-	"CHANNEL_PINS_UPDATE":        ChannelPinsUpdate{},
-	"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{},
-	"GUILD_MEMBERS_CHUNK":        GuildMembersChunk{},
-	"MESSAGE_ACK":                MessageAck{},
-	"MESSAGE_CREATE":             MessageCreate{},
-	"MESSAGE_UPDATE":             MessageUpdate{},
-	"MESSAGE_DELETE":             MessageDelete{},
-	"MESSAGE_REACTION_ADD":       MessageReactionAdd{},
-	"MESSAGE_REACTION_REMOVE":    MessageReactionRemove{},
-	"PRESENCE_UPDATE":            PresenceUpdate{},
-	"PRESENCES_REPLACE":          PresencesReplace{},
-	"READY":                      Ready{},
-	"RELATIONSHIP_ADD":           RelationshipAdd{},
-	"RELATIONSHIP_REMOVE":        RelationshipRemove{},
-	"USER_UPDATE":                UserUpdate{},
-	"USER_SETTINGS_UPDATE":       UserSettingsUpdate{},
-	"USER_GUILD_SETTINGS_UPDATE": UserGuildSettingsUpdate{},
-	"TYPING_START":               TypingStart{},
-	"VOICE_SERVER_UPDATE":        VoiceServerUpdate{},
-	"VOICE_STATE_UPDATE":         VoiceStateUpdate{},
-	"RESUMED":                    Resumed{},
-}
-
-// Connect is an empty struct for an event.
+import (
+	"encoding/json"
+	"time"
+)
+
+// This file contains all the possible structs that can be
+// handled by AddHandler/EventHandler.
+// DO NOT ADD ANYTHING BUT EVENT HANDLER STRUCTS TO THIS FILE.
+//go:generate go run tools/cmd/eventhandlers/main.go
+
+// Connect is the data for a Connect event.
+// This is a sythetic event and is not dispatched by Discord.
 type Connect struct{}
 
-// Disconnect is an empty struct for an event.
+// Disconnect is the data for a Disconnect event.
+// This is a sythetic event and is not dispatched by Discord.
 type Disconnect struct{}
 
-// RateLimit is a struct for the RateLimited event
+// RateLimit is the data for a RateLimit event.
+// This is a sythetic event and is not dispatched by Discord.
 type RateLimit struct {
 	*TooManyRequests
 	URL string
 }
 
-// MessageCreate is a wrapper struct for an event.
-type MessageCreate struct {
-	*Message
-}
-
-// MessageUpdate is a wrapper struct for an event.
-type MessageUpdate struct {
-	*Message
-}
-
-// MessageDelete is a wrapper struct for an event.
-type MessageDelete struct {
-	*Message
+// Event provides a basic initial struct for all websocket events.
+type Event struct {
+	Operation int             `json:"op"`
+	Sequence  int             `json:"s"`
+	Type      string          `json:"t"`
+	RawData   json.RawMessage `json:"d"`
+	// Struct contains one of the other types in this file.
+	Struct interface{} `json:"-"`
 }
 
-// MessageReactionAdd is a wrapper struct for an event.
-type MessageReactionAdd struct {
-	*MessageReaction
-}
+// A Ready stores all data for the websocket READY event.
+type Ready struct {
+	Version           int           `json:"v"`
+	SessionID         string        `json:"session_id"`
+	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
+	User              *User         `json:"user"`
+	ReadState         []*ReadState  `json:"read_state"`
+	PrivateChannels   []*Channel    `json:"private_channels"`
+	Guilds            []*Guild      `json:"guilds"`
 
-// MessageReactionRemove is a wrapper struct for an event.
-type MessageReactionRemove struct {
-	*MessageReaction
+	// Undocumented fields
+	Settings          *Settings            `json:"user_settings"`
+	UserGuildSettings []*UserGuildSettings `json:"user_guild_settings"`
+	Relationships     []*Relationship      `json:"relationships"`
+	Presences         []*Presence          `json:"presences"`
 }
 
-// ChannelCreate is a wrapper struct for an event.
+// ChannelCreate is the data for a ChannelCreate event.
 type ChannelCreate struct {
 	*Channel
 }
 
-// ChannelUpdate is a wrapper struct for an event.
+// ChannelUpdate is the data for a ChannelUpdate event.
 type ChannelUpdate struct {
 	*Channel
 }
 
-// ChannelDelete is a wrapper struct for an event.
+// ChannelDelete is the data for a ChannelDelete event.
 type ChannelDelete struct {
 	*Channel
 }
 
-// GuildCreate is a wrapper struct for an event.
+// ChannelPinsUpdate stores data for a ChannelPinsUpdate event.
+type ChannelPinsUpdate struct {
+	LastPinTimestamp string `json:"last_pin_timestamp"`
+	ChannelID        string `json:"channel_id"`
+}
+
+// GuildCreate is the data for a GuildCreate event.
 type GuildCreate struct {
 	*Guild
 }
 
-// GuildUpdate is a wrapper struct for an event.
+// GuildUpdate is the data for a GuildUpdate event.
 type GuildUpdate struct {
 	*Guild
 }
 
-// GuildDelete is a wrapper struct for an event.
+// GuildDelete is the data for a GuildDelete event.
 type GuildDelete struct {
 	*Guild
 }
 
-// GuildBanAdd is a wrapper struct for an event.
+// GuildBanAdd is the data for a GuildBanAdd event.
 type GuildBanAdd struct {
 	User    *User  `json:"user"`
 	GuildID string `json:"guild_id"`
 }
 
-// GuildBanRemove is a wrapper struct for an event.
+// GuildBanRemove is the data for a GuildBanRemove event.
 type GuildBanRemove struct {
 	User    *User  `json:"user"`
 	GuildID string `json:"guild_id"`
 }
 
-// GuildMemberAdd is a wrapper struct for an event.
+// GuildMemberAdd is the data for a GuildMemberAdd event.
 type GuildMemberAdd struct {
 	*Member
 }
 
-// GuildMemberUpdate is a wrapper struct for an event.
+// GuildMemberUpdate is the data for a GuildMemberUpdate event.
 type GuildMemberUpdate struct {
 	*Member
 }
 
-// GuildMemberRemove is a wrapper struct for an event.
+// GuildMemberRemove is the data for a GuildMemberRemove event.
 type GuildMemberRemove struct {
 	*Member
 }
 
-// GuildRoleCreate is a wrapper struct for an event.
+// GuildRoleCreate is the data for a GuildRoleCreate event.
 type GuildRoleCreate struct {
 	*GuildRole
 }
 
-// GuildRoleUpdate is a wrapper struct for an event.
+// GuildRoleUpdate is the data for a GuildRoleUpdate event.
 type GuildRoleUpdate struct {
 	*GuildRole
 }
 
-// PresencesReplace is an array of Presences for an event.
+// A GuildRoleDelete is the data for a GuildRoleDelete event.
+type GuildRoleDelete struct {
+	RoleID  string `json:"role_id"`
+	GuildID string `json:"guild_id"`
+}
+
+// A GuildEmojisUpdate is the data for a guild emoji update event.
+type GuildEmojisUpdate struct {
+	GuildID string   `json:"guild_id"`
+	Emojis  []*Emoji `json:"emojis"`
+}
+
+// A GuildMembersChunk is the data for a GuildMembersChunk event.
+type GuildMembersChunk struct {
+	GuildID string    `json:"guild_id"`
+	Members []*Member `json:"members"`
+}
+
+// GuildIntegrationsUpdate is the data for a GuildIntegrationsUpdate event.
+type GuildIntegrationsUpdate struct {
+	GuildID string `json:"guild_id"`
+}
+
+// MessageAck is the data for a MessageAck event.
+type MessageAck struct {
+	MessageID string `json:"message_id"`
+	ChannelID string `json:"channel_id"`
+}
+
+// MessageCreate is the data for a MessageCreate event.
+type MessageCreate struct {
+	*Message
+}
+
+// MessageUpdate is the data for a MessageUpdate event.
+type MessageUpdate struct {
+	*Message
+}
+
+// MessageDelete is the data for a MessageDelete event.
+type MessageDelete struct {
+	*Message
+}
+
+// MessageReactionAdd is the data for a MessageReactionAdd event.
+type MessageReactionAdd struct {
+	*MessageReaction
+}
+
+// MessageReactionRemove is the data for a MessageReactionRemove event.
+type MessageReactionRemove struct {
+	*MessageReaction
+}
+
+// PresencesReplace is the data for a PresencesReplace event.
 type PresencesReplace []*Presence
 
-// RelationshipAdd is a wrapper struct for an event.
+// PresenceUpdate is the data for a PresenceUpdate event.
+type PresenceUpdate struct {
+	Presence
+	GuildID string   `json:"guild_id"`
+	Roles   []string `json:"roles"`
+}
+
+// Resumed is the data for a Resumed event.
+type Resumed struct {
+	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
+	Trace             []string      `json:"_trace"`
+}
+
+// RelationshipAdd is the data for a RelationshipAdd event.
 type RelationshipAdd struct {
 	*Relationship
 }
 
-// RelationshipRemove is a wrapper struct for an event.
+// RelationshipRemove is the data for a RelationshipRemove event.
 type RelationshipRemove struct {
 	*Relationship
 }
 
-// VoiceStateUpdate is a wrapper struct for an event.
-type VoiceStateUpdate struct {
-	*VoiceState
+// TypingStart is the data for a TypingStart event.
+type TypingStart struct {
+	UserID    string `json:"user_id"`
+	ChannelID string `json:"channel_id"`
+	Timestamp int    `json:"timestamp"`
 }
 
-// UserUpdate is a wrapper struct for an event.
+// UserUpdate is the data for a UserUpdate event.
 type UserUpdate struct {
 	*User
 }
 
-// UserSettingsUpdate is a map for an event.
+// UserSettingsUpdate is the data for a UserSettingsUpdate event.
 type UserSettingsUpdate map[string]interface{}
 
-// UserGuildSettingsUpdate is a map for an event.
+// UserGuildSettingsUpdate is the data for a UserGuildSettingsUpdate event.
 type UserGuildSettingsUpdate struct {
 	*UserGuildSettings
 }
+
+// VoiceServerUpdate is the data for a VoiceServerUpdate event.
+type VoiceServerUpdate struct {
+	Token    string `json:"token"`
+	GuildID  string `json:"guild_id"`
+	Endpoint string `json:"endpoint"`
+}
+
+// VoiceStateUpdate is the data for a VoiceStateUpdate event.
+type VoiceStateUpdate struct {
+	*VoiceState
+}

+ 1 - 1
restapi.go

@@ -146,7 +146,7 @@ func (s *Session) request(method, urlStr, contentType string, b []byte, bucketID
 			return
 		}
 		s.log(LogInformational, "Rate Limiting %s, retry in %d", urlStr, rl.RetryAfter)
-		s.handle(RateLimit{TooManyRequests: &rl, URL: urlStr})
+		s.handleEvent(rateLimitEventType, RateLimit{TooManyRequests: &rl, URL: urlStr})
 
 		time.Sleep(rl.RetryAfter * time.Millisecond)
 		// we can make the above smarter

+ 5 - 91
structs.go

@@ -13,7 +13,6 @@ package discordgo
 
 import (
 	"encoding/json"
-	"reflect"
 	"strconv"
 	"sync"
 	"time"
@@ -74,13 +73,10 @@ type Session struct {
 	// StateEnabled is true.
 	State *State
 
-	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
-	// the function each event.
-	handlers map[interface{}][]reflect.Value
+	// Event handlers
+	handlersMu   sync.RWMutex
+	handlers     map[string][]*eventHandlerInstance
+	onceHandlers map[string][]*eventHandlerInstance
 
 	// The websocket connection.
 	wsConn *websocket.Conn
@@ -110,12 +106,6 @@ type rateLimitMutex struct {
 	// bucket map[string]*sync.Mutex // TODO :)
 }
 
-// A Resumed struct holds the data received in a RESUMED event
-type Resumed struct {
-	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
-	Trace             []string      `json:"_trace"`
-}
-
 // A VoiceRegion stores data for a specific voice region server.
 type VoiceRegion struct {
 	ID       string `json:"id"`
@@ -385,32 +375,6 @@ type FriendSourceFlags struct {
 	MutualFriends bool `json:"mutual_friends"`
 }
 
-// An Event provides a basic initial struct for all websocket event.
-type Event struct {
-	Operation int             `json:"op"`
-	Sequence  int             `json:"s"`
-	Type      string          `json:"t"`
-	RawData   json.RawMessage `json:"d"`
-	Struct    interface{}     `json:"-"`
-}
-
-// A Ready stores all data for the websocket READY event.
-type Ready struct {
-	Version           int           `json:"v"`
-	SessionID         string        `json:"session_id"`
-	HeartbeatInterval time.Duration `json:"heartbeat_interval"`
-	User              *User         `json:"user"`
-	ReadState         []*ReadState  `json:"read_state"`
-	PrivateChannels   []*Channel    `json:"private_channels"`
-	Guilds            []*Guild      `json:"guilds"`
-
-	// Undocumented fields
-	Settings          *Settings            `json:"user_settings"`
-	UserGuildSettings []*UserGuildSettings `json:"user_guild_settings"`
-	Relationships     []*Relationship      `json:"relationships"`
-	Presences         []*Presence          `json:"presences"`
-}
-
 // A Relationship between the logged in user and Relationship.User
 type Relationship struct {
 	User *User  `json:"user"`
@@ -433,67 +397,23 @@ type ReadState struct {
 	ID            string `json:"id"`
 }
 
-// A TypingStart stores data for the typing start websocket event.
-type TypingStart struct {
-	UserID    string `json:"user_id"`
-	ChannelID string `json:"channel_id"`
-	Timestamp int    `json:"timestamp"`
-}
-
-// A PresenceUpdate stores data for the presence update websocket event.
-type PresenceUpdate struct {
-	Presence
-	GuildID string   `json:"guild_id"`
-	Roles   []string `json:"roles"`
-}
-
-// A MessageAck stores data for the message ack websocket event.
-type MessageAck struct {
-	MessageID string `json:"message_id"`
-	ChannelID string `json:"channel_id"`
-}
-
 // An Ack is used to ack messages
 type Ack struct {
 	Token string `json:"token"`
 }
 
-// A GuildIntegrationsUpdate stores data for the guild integrations update
-// websocket event.
-type GuildIntegrationsUpdate struct {
-	GuildID string `json:"guild_id"`
-}
-
-// A GuildRole stores data for guild role websocket events.
+// A GuildRole stores data for guild roles.
 type GuildRole struct {
 	Role    *Role  `json:"role"`
 	GuildID string `json:"guild_id"`
 }
 
-// A GuildRoleDelete stores data for the guild role delete websocket event.
-type GuildRoleDelete struct {
-	RoleID  string `json:"role_id"`
-	GuildID string `json:"guild_id"`
-}
-
 // A GuildBan stores data for a guild ban.
 type GuildBan struct {
 	Reason string `json:"reason"`
 	User   *User  `json:"user"`
 }
 
-// A GuildEmojisUpdate stores data for a guild emoji update event.
-type GuildEmojisUpdate struct {
-	GuildID string   `json:"guild_id"`
-	Emojis  []*Emoji `json:"emojis"`
-}
-
-// A GuildMembersChunk stores data for the Guild Members Chunk websocket event.
-type GuildMembersChunk struct {
-	GuildID string    `json:"guild_id"`
-	Members []*Member `json:"members"`
-}
-
 // A GuildIntegration stores data for a guild integration.
 type GuildIntegration struct {
 	ID                string                   `json:"id"`
@@ -553,12 +473,6 @@ type APIErrorMessage struct {
 	Message string `json:"message"`
 }
 
-// ChannelPinsUpdate stores data for the channel pins update event
-type ChannelPinsUpdate struct {
-	LastPinTimestamp string `json:"last_pin_timestamp"`
-	ChannelID        string `json:"channel_id"`
-}
-
 // Webhook stores the data for a webhook.
 type Webhook struct {
 	ID        string `json:"id"`

+ 123 - 0
tools/cmd/eventhandlers/main.go

@@ -0,0 +1,123 @@
+package main
+
+import (
+	"bytes"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io/ioutil"
+	"log"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strings"
+	"text/template"
+)
+
+var eventHandlerTmpl = template.Must(template.New("eventHandler").Funcs(template.FuncMap{
+	"constName":      constName,
+	"isDiscordEvent": isDiscordEvent,
+	"privateName":    privateName,
+}).Parse(`// Code generated by \"eventhandlers\"; DO NOT EDIT
+// See events.go
+
+package discordgo
+
+// Following are all the event types.
+// Event type values are used to match the events returned by Discord.
+// EventTypes surrounded by __ are synthetic and are internal to DiscordGo.
+const ({{range .}}
+  {{privateName .}}EventType = "{{constName .}}"{{end}}
+)
+{{range .}}
+// {{privateName .}}EventHandler is an event handler for {{.}} events.
+type {{privateName .}}EventHandler func(*Session, *{{.}})
+
+// Type returns the event type for {{.}} events.
+func (eh {{privateName .}}EventHandler) Type() string {
+  return {{privateName .}}EventType
+}
+
+// New returns a new instance of {{.}}.
+func (eh {{privateName .}}EventHandler) New() interface{} {
+  return &{{.}}{}
+}
+
+// Handle is the handler for {{.}} events.
+func (eh {{privateName .}}EventHandler) Handle(s *Session, i interface{}) {
+  if t, ok := i.(*{{.}}); ok {
+    eh(s, t)
+  }
+}
+{{end}}
+func handlerForInterface(handler interface{}) EventHandler {
+  switch v := handler.(type) {
+  case func(*Session, interface{}):
+    return interfaceEventHandler(v){{range .}}
+  case func(*Session, *{{.}}):
+    return {{privateName .}}EventHandler(v){{end}}
+  }
+
+  return nil
+}
+func init() { {{range .}}{{if isDiscordEvent .}}
+  registerInterfaceProvider({{privateName .}}EventHandler(nil)){{end}}{{end}}
+}
+`))
+
+func main() {
+	var buf bytes.Buffer
+	dir := filepath.Dir(".")
+
+	fs := token.NewFileSet()
+	parsedFile, err := parser.ParseFile(fs, "events.go", nil, 0)
+	if err != nil {
+		log.Fatalf("warning: internal error: could not parse events.go: %s", err)
+		return
+	}
+
+	names := []string{}
+	for object := range parsedFile.Scope.Objects {
+		names = append(names, object)
+	}
+	sort.Strings(names)
+	eventHandlerTmpl.Execute(&buf, names)
+
+	src, err := format.Source(buf.Bytes())
+	if err != nil {
+		log.Println("warning: internal error: invalid Go generated:", err)
+		src = buf.Bytes()
+	}
+
+	err = ioutil.WriteFile(filepath.Join(dir, strings.ToLower("eventhandlers.go")), src, 0644)
+	if err != nil {
+		log.Fatal(buf, "writing output: %s", err)
+	}
+}
+
+var constRegexp = regexp.MustCompile("([a-z])([A-Z])")
+
+func constCase(name string) string {
+	return strings.ToUpper(constRegexp.ReplaceAllString(name, "${1}_${2}"))
+}
+
+func isDiscordEvent(name string) bool {
+	switch {
+	case name == "Connect", name == "Disconnect", name == "Event", name == "RateLimit", name == "Interface":
+		return false
+	default:
+		return true
+	}
+}
+
+func constName(name string) string {
+	if !isDiscordEvent(name) {
+		return "__" + constCase(name) + "__"
+	}
+
+	return constCase(name)
+}
+
+func privateName(name string) string {
+	return strings.ToLower(string(name[0])) + name[1:]
+}

+ 9 - 26
wsapi.go

@@ -18,7 +18,6 @@ import (
 	"fmt"
 	"io"
 	"net/http"
-	"reflect"
 	"runtime"
 	"time"
 
@@ -121,9 +120,8 @@ func (s *Session) Open() (err error) {
 
 	s.Unlock()
 
-	s.initialize()
 	s.log(LogInformational, "emit connect event")
-	s.handle(&Connect{})
+	s.handleEvent(connectEventType, &Connect{})
 
 	s.log(LogInformational, "exiting")
 	return
@@ -409,16 +407,12 @@ func (s *Session) onEvent(messageType int, message []byte) {
 	// Store the message sequence
 	s.sequence = e.Sequence
 
-	// Map event to registered event handlers and pass it along
-	// to any registered functions
-	i := eventToInterface[e.Type]
-	if i != nil {
-
-		// Create a new instance of the event type.
-		i = reflect.New(reflect.TypeOf(i)).Interface()
+	// Map event to registered event handlers and pass it along to any registered handlers.
+	if eh, ok := registeredInterfaceProviders[e.Type]; ok {
+		e.Struct = eh.New()
 
 		// Attempt to unmarshal our event.
-		if err = json.Unmarshal(e.RawData, i); err != nil {
+		if err = json.Unmarshal(e.RawData, e.Struct); err != nil {
 			s.log(LogError, "error unmarshalling %s event, %s", e.Type, err)
 		}
 
@@ -429,30 +423,19 @@ func (s *Session) onEvent(messageType int, message []byte) {
 		// it's better to pass along what we received than nothing at all.
 		// TODO: Think about that decision :)
 		// Either way, READY events must fire, even with errors.
-		go s.handle(i)
-
+		s.handleEvent(e.Type, e.Struct)
 	} else {
 		s.log(LogWarning, "unknown event: Op: %d, Seq: %d, Type: %s, Data: %s", e.Operation, e.Sequence, e.Type, string(e.RawData))
 	}
 
-	// Emit event to the OnEvent handler
-	e.Struct = i
-	go s.handle(e)
+	// For legacy reasons, we send the raw event also, this could be useful for handling unknown events.
+	s.handleEvent(eventEventType, e)
 }
 
 // ------------------------------------------------------------------------------------------------
 // Code related to voice connections that initiate over the data websocket
 // ------------------------------------------------------------------------------------------------
 
-// A VoiceServerUpdate stores the data received during the Voice Server Update
-// data websocket event. This data is used during the initial Voice Channel
-// join handshaking.
-type VoiceServerUpdate struct {
-	Token    string `json:"token"`
-	GuildID  string `json:"guild_id"`
-	Endpoint string `json:"endpoint"`
-}
-
 type voiceChannelJoinData struct {
 	GuildID   *string `json:"guild_id"`
 	ChannelID *string `json:"channel_id"`
@@ -712,7 +695,7 @@ func (s *Session) Close() (err error) {
 	s.Unlock()
 
 	s.log(LogInformational, "emit disconnect event")
-	s.handle(&Disconnect{})
+	s.handleEvent(disconnectEventType, &Disconnect{})
 
 	return
 }