2016-05-18 22:11:10 +02:00
|
|
|
package gosocketio
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2016-05-22 20:04:25 +02:00
|
|
|
"reflect"
|
2018-09-19 11:59:27 +02:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"forge.cadoles.com/Pyxis/golang-socketio/protocol"
|
2016-05-18 22:11:10 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
OnConnection = "connection"
|
|
|
|
OnDisconnection = "disconnection"
|
|
|
|
OnError = "error"
|
|
|
|
)
|
|
|
|
|
|
|
|
/**
|
|
|
|
System handler function for internal event processing
|
|
|
|
*/
|
|
|
|
type systemHandler func(c *Channel)
|
|
|
|
|
|
|
|
/**
|
|
|
|
Contains maps of message processing functions
|
|
|
|
*/
|
|
|
|
type methods struct {
|
|
|
|
messageHandlers map[string]*caller
|
|
|
|
messageHandlersLock sync.RWMutex
|
|
|
|
|
|
|
|
onConnection systemHandler
|
|
|
|
onDisconnection systemHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
create messageHandlers map
|
|
|
|
*/
|
|
|
|
func (m *methods) initMethods() {
|
|
|
|
m.messageHandlers = make(map[string]*caller)
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Add message processing function, and bind it to given method
|
|
|
|
*/
|
|
|
|
func (m *methods) On(method string, f interface{}) error {
|
|
|
|
c, err := newCaller(f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
m.messageHandlersLock.Lock()
|
|
|
|
defer m.messageHandlersLock.Unlock()
|
|
|
|
m.messageHandlers[method] = c
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-09-19 11:59:27 +02:00
|
|
|
/**
|
|
|
|
Remove message processing function
|
|
|
|
*/
|
|
|
|
func (m *methods) Off(method string) {
|
|
|
|
m.messageHandlersLock.Lock()
|
|
|
|
defer m.messageHandlersLock.Unlock()
|
|
|
|
delete(m.messageHandlers, method)
|
|
|
|
}
|
|
|
|
|
2016-05-18 22:11:10 +02:00
|
|
|
/**
|
|
|
|
Find message processing function associated with given method
|
|
|
|
*/
|
|
|
|
func (m *methods) findMethod(method string) (*caller, bool) {
|
|
|
|
m.messageHandlersLock.RLock()
|
|
|
|
defer m.messageHandlersLock.RUnlock()
|
|
|
|
|
|
|
|
f, ok := m.messageHandlers[method]
|
|
|
|
return f, ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *methods) callLoopEvent(c *Channel, event string) {
|
|
|
|
if m.onConnection != nil && event == OnConnection {
|
|
|
|
m.onConnection(c)
|
|
|
|
}
|
|
|
|
if m.onDisconnection != nil && event == OnDisconnection {
|
|
|
|
m.onDisconnection(c)
|
|
|
|
}
|
|
|
|
|
|
|
|
f, ok := m.findMethod(event)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
f.callFunc(c, &struct{}{})
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Check incoming message
|
|
|
|
On ack_resp - look for waiter
|
|
|
|
On ack_req - look for processing function and send ack_resp
|
|
|
|
On emit - look for processing function
|
|
|
|
*/
|
|
|
|
func (m *methods) processIncomingMessage(c *Channel, msg *protocol.Message) {
|
|
|
|
switch msg.Type {
|
|
|
|
case protocol.MessageTypeEmit:
|
|
|
|
f, ok := m.findMethod(msg.Method)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-22 20:04:25 +02:00
|
|
|
if !f.ArgsPresent {
|
|
|
|
f.callFunc(c, &struct{}{})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-18 22:11:10 +02:00
|
|
|
data := f.getArgs()
|
|
|
|
err := json.Unmarshal([]byte(msg.Args), &data)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
f.callFunc(c, data)
|
|
|
|
|
|
|
|
case protocol.MessageTypeAckRequest:
|
|
|
|
f, ok := m.findMethod(msg.Method)
|
|
|
|
if !ok || !f.Out {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-22 20:04:25 +02:00
|
|
|
var result []reflect.Value
|
|
|
|
if f.ArgsPresent {
|
|
|
|
//data type should be defined for unmarshall
|
|
|
|
data := f.getArgs()
|
|
|
|
err := json.Unmarshal([]byte(msg.Args), &data)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
result = f.callFunc(c, data)
|
|
|
|
} else {
|
|
|
|
result = f.callFunc(c, &struct{}{})
|
2016-05-18 22:11:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ack := &protocol.Message{
|
|
|
|
Type: protocol.MessageTypeAckResponse,
|
|
|
|
AckId: msg.AckId,
|
|
|
|
}
|
|
|
|
send(ack, c, result[0].Interface())
|
|
|
|
|
|
|
|
case protocol.MessageTypeAckResponse:
|
|
|
|
waiter, err := c.ack.getWaiter(msg.AckId)
|
|
|
|
if err == nil {
|
|
|
|
waiter <- msg.Args
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|