Clean up Gateway API Event handling.
This commit is contained in:
parent
a24f9e3d10
commit
2ac4665a4e
1 changed files with 42 additions and 29 deletions
71
wsapi.go
71
wsapi.go
|
@ -167,7 +167,10 @@ func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
|
||||||
case <-listening:
|
case <-listening:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
go s.event(messageType, message)
|
// TODO make s.event a variable that points to a function
|
||||||
|
// this way it will be possible for an end-user to write
|
||||||
|
// a completely custom event handler if needed.
|
||||||
|
go s.onEvent(messageType, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,73 +248,83 @@ func (s *Session) UpdateStatus(idle int, game string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Front line handler for all Websocket Events. Determines the
|
// onEvent is the "event handler" for all messages received on the
|
||||||
// event type and passes the message along to the next handler.
|
// Discord Gateway API websocket connection.
|
||||||
|
//
|
||||||
|
// If you use the AddHandler() function to register a handler for a
|
||||||
|
// specific event this function will pass the event along to that handler.
|
||||||
|
//
|
||||||
|
// If you use the AddHandler() function to register a handler for the
|
||||||
|
// "OnEvent" event then all events will be passed to that handler.
|
||||||
|
//
|
||||||
|
// TODO: You may also register a custom event handler entirely using...
|
||||||
|
func (s *Session) onEvent(messageType int, message []byte) {
|
||||||
|
|
||||||
// event is the front line handler for all events. This needs to be
|
|
||||||
// broken up into smaller functions to be more idiomatic Go.
|
|
||||||
// Events will be handled by any implemented handler in Session.
|
|
||||||
// All unhandled events will then be handled by OnEvent.
|
|
||||||
func (s *Session) event(messageType int, message []byte) {
|
|
||||||
var err error
|
var err error
|
||||||
var reader io.Reader
|
var reader io.Reader
|
||||||
|
|
||||||
reader = bytes.NewBuffer(message)
|
reader = bytes.NewBuffer(message)
|
||||||
|
|
||||||
|
// If this is a compressed message, uncompress it.
|
||||||
if messageType == 2 {
|
if messageType == 2 {
|
||||||
z, err1 := zlib.NewReader(reader)
|
|
||||||
if err1 != nil {
|
z, err := zlib.NewReader(reader)
|
||||||
log.Println(fmt.Sprintf("Error uncompressing message type %d: %s", messageType, err1))
|
if err != nil {
|
||||||
|
s.log(LogError, "error uncompressing websocket message, %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := z.Close()
|
err := z.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("error closing zlib:", err)
|
s.log(LogWarning, "error closing zlib, %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
reader = z
|
reader = z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode the event into an Event struct.
|
||||||
var e *Event
|
var e *Event
|
||||||
decoder := json.NewDecoder(reader)
|
decoder := json.NewDecoder(reader)
|
||||||
if err = decoder.Decode(&e); err != nil {
|
if err = decoder.Decode(&e); err != nil {
|
||||||
log.Println(fmt.Sprintf("Error decoding message type %d: %s", messageType, err))
|
s.log(LogError, "error decoding websocket message, %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Debug {
|
if s.Debug { // TODO: refactor using s.log()
|
||||||
printEvent(e)
|
printEvent(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Map event to registered event handlers and pass it along
|
||||||
|
// to any registered functions
|
||||||
i := eventToInterface[e.Type]
|
i := eventToInterface[e.Type]
|
||||||
if i != nil {
|
if i != nil {
|
||||||
|
|
||||||
// Create a new instance of the event type.
|
// Create a new instance of the event type.
|
||||||
i = reflect.New(reflect.TypeOf(i)).Interface()
|
i = reflect.New(reflect.TypeOf(i)).Interface()
|
||||||
|
|
||||||
// Attempt to unmarshal our event.
|
// Attempt to unmarshal our event.
|
||||||
// If there is an error we should handle the event itself.
|
|
||||||
if err = json.Unmarshal(e.RawData, i); err != nil {
|
if err = json.Unmarshal(e.RawData, i); err != nil {
|
||||||
log.Printf("error unmarshalling %s event, %s\n", e.Type, err)
|
s.log(LogError, "error unmarshalling %s event, %s", e.Type, err)
|
||||||
// Ready events must fire, even if they are empty.
|
|
||||||
if e.Type != "READY" {
|
|
||||||
i = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
// Send event to any registered event handlers for it's type.
|
||||||
} else {
|
// Because the above doesn't cancel this, in case of an error
|
||||||
log.Println("Unknown event.")
|
// the struct could be partially populated or at default values.
|
||||||
i = nil
|
// However, most errors are due to a single field and I feel
|
||||||
}
|
// it's better to pass along what we received than nothing at all.
|
||||||
|
// TODO: Think about that decision :)
|
||||||
if i != nil {
|
// Either way, READY events must fire, even with errors.
|
||||||
s.handle(i)
|
s.handle(i)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
s.log(LogWarning, "unknown event type %s", e.Type)
|
||||||
|
printEvent(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit event to the OnEvent handler
|
||||||
e.Struct = i
|
e.Struct = i
|
||||||
s.handle(e)
|
s.handle(e)
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue