Small performance improvement. Added tests.

This commit is contained in:
Chris Rhodes 2016-02-14 19:01:45 -08:00
parent 6fa99712ef
commit 88335b6f54
3 changed files with 50 additions and 6 deletions

View file

@ -151,10 +151,10 @@ func (s *Session) AddHandler(handler interface{}) {
handlers := s.Handlers[eventType] handlers := s.Handlers[eventType]
if handlers == nil { if handlers == nil {
handlers = []interface{}{} handlers = []reflect.Value{}
} }
handlers = append(handlers, handler) handlers = append(handlers, reflect.ValueOf(handler))
s.Handlers[eventType] = handlers s.Handlers[eventType] = handlers
} }
@ -162,15 +162,17 @@ func (s *Session) handle(event interface{}) {
s.RLock() s.RLock()
defer s.RUnlock() defer s.RUnlock()
handlerParameters := []reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}
if handlers, ok := s.Handlers[reflect.TypeOf(event)]; ok { if handlers, ok := s.Handlers[reflect.TypeOf(event)]; ok {
for _, handler := range handlers { for _, handler := range handlers {
reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}) handler.Call(handlerParameters)
} }
} }
if handlers, ok := s.Handlers[nil]; ok { if handlers, ok := s.Handlers[nil]; ok {
for _, handler := range handlers { for _, handler := range handlers {
reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}) handler.Call(handlerParameters)
} }
} }
} }
@ -178,7 +180,7 @@ func (s *Session) handle(event interface{}) {
// initialize adds all internal handlers and state tracking handlers. // initialize adds all internal handlers and state tracking handlers.
func (s *Session) initialize() { func (s *Session) initialize() {
s.Lock() s.Lock()
s.Handlers = map[interface{}][]interface{}{} s.Handlers = map[interface{}][]reflect.Value{}
s.Unlock() s.Unlock()
s.AddHandler(s.onEvent) s.AddHandler(s.onEvent)

View file

@ -224,3 +224,39 @@ func TestOpenClose(t *testing.T) {
t.Fatalf("TestClose, d.Close failed: %+v", err) t.Fatalf("TestClose, d.Close failed: %+v", err)
} }
} }
func TestHandlers(t *testing.T) {
testHandlerCalled := false
testHandler := func(s *Session, t *testing.T) {
testHandlerCalled = true
}
interfaceHandlerCalled := false
interfaceHandler := func(s *Session, i interface{}) {
interfaceHandlerCalled = true
}
bogusHandlerCalled := false
bogusHandler := func(s *Session, se *Session) {
bogusHandlerCalled = true
}
d := Session{}
d.AddHandler(testHandler)
d.AddHandler(interfaceHandler)
d.AddHandler(bogusHandler)
d.handle(t)
if !testHandlerCalled {
t.Fatalf("testHandler was not called.")
}
if !interfaceHandlerCalled {
t.Fatalf("interfaceHandler was not called.")
}
if bogusHandlerCalled {
t.Fatalf("bogusHandler was called.")
}
}

View file

@ -13,6 +13,7 @@ package discordgo
import ( import (
"encoding/json" "encoding/json"
"reflect"
"sync" "sync"
"time" "time"
@ -29,7 +30,12 @@ type Session struct {
Token string // Authentication token for this session Token string // Authentication token for this session
Debug bool // Debug for printing JSON request/responses Debug bool // Debug for printing JSON request/responses
Handlers map[interface{}][]interface{} // This is a mapping of event structs 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
// Exposed but should not be modified by User. // Exposed but should not be modified by User.
SessionID string // from websocket READY packet SessionID string // from websocket READY packet