graarh / golang-socketio

golang socket.io client and server
GNU General Public License v3.0
435 stars 260 forks source link

move json decode/encode to user code? #17

Open oldshuren opened 7 years ago

oldshuren commented 7 years ago

I think handler.go should detect that if the user callback argument is string type. Just call the callback directly without json.Unmarshall. Same for send.go, if the args type is string, don't call json.Marshall.

Because sometimes we want just to a partial json decoding. Or we can use easyjson's generated code to do Marshall/Unmarshall

Thanks!

kdar commented 7 years ago

For the time being, you can just use json.RawMessage as the parameter and get a byte slice. I'm sure type checking would perform better though.

freman commented 7 years ago

That's not working for me :D

It turns out our upstream service is... unique and is sending back 3 parameters...

{"some":"json":"blob":true},"{\"status\":200,\"data\":{},\"message\":\"Ok\"}",6895206,

original request, response, some integer

json.RawMessage doesn't let me parse it, interface, string, []byte...

Always end up with invalid character ',' after top-level value

edit: Raw frame:

42["deferred",{"some":"json":"blob":true},"{\"status\":200,\"data\":{},\"message\":\"Ok\"}",6895206]

edit: I solved mine with the following patch which permits on funcs with multiple arguments

diff --git a/caller.go b/caller.go
index bb423dd..5d25108 100644
--- a/caller.go
+++ b/caller.go
@@ -7,7 +7,7 @@ import (

 type caller struct {
    Func        reflect.Value
-   Args        reflect.Type
+   Args        []reflect.Type
    ArgsPresent bool
    Out         bool
 }
@@ -40,8 +40,11 @@ func newCaller(f interface{}) (*caller, error) {
    if fType.NumIn() == 1 {
        curCaller.Args = nil
        curCaller.ArgsPresent = false
-   } else if fType.NumIn() == 2 {
-       curCaller.Args = fType.In(1)
+   } else if fType.NumIn() >= 2 {
+       curCaller.Args = make([]reflect.Type, fType.NumIn()-1)
+       for i := range curCaller.Args {
+           curCaller.Args[i] = fType.In(i + 1)
+       }
        curCaller.ArgsPresent = true
    } else {
        return nil, ErrorCallerNot2Args
@@ -53,23 +56,27 @@ func newCaller(f interface{}) (*caller, error) {
 /**
 returns function parameter as it is present in it using reflection
 */
-func (c *caller) getArgs() interface{} {
-   return reflect.New(c.Args).Interface()
+func (c *caller) getArgs() []interface{} {
+   res := make([]interface{}, len(c.Args))
+   for i, v := range c.Args {
+       res[i] = reflect.New(v).Interface()
+   }
+   return res
 }

 /**
 calls function with given arguments from its representation using reflection
 */
-func (c *caller) callFunc(h *Channel, args interface{}) []reflect.Value {
+func (c *caller) callFunc(h *Channel, args []interface{}) []reflect.Value {
    //nil is untyped, so use the default empty value of correct type
    if args == nil {
        args = c.getArgs()
    }
-
-   a := []reflect.Value{reflect.ValueOf(h), reflect.ValueOf(args).Elem()}
-   if !c.ArgsPresent {
-       a = a[0:1]
+   vals := make([]reflect.Value, len(args)+1)
+   vals[0] = reflect.ValueOf(h)
+   for i, v := range args {
+       vals[i+1] = reflect.ValueOf(v).Elem()
    }

-   return c.Func.Call(a)
+   return c.Func.Call(vals)
 }
diff --git a/handler.go b/handler.go
index 78c3636..59cce04 100644
--- a/handler.go
+++ b/handler.go
@@ -2,9 +2,11 @@ package gosocketio

 import (
    "encoding/json"
-   "github.com/graarh/golang-socketio/protocol"
-   "sync"
+   "fmt"
    "reflect"
+   "sync"
+
+   "github.com/graarh/golang-socketio/protocol"
 )

 const (
@@ -48,7 +50,6 @@ func (m *methods) On(method string, f interface{}) error {
    m.messageHandlersLock.Lock()
    defer m.messageHandlersLock.Unlock()
    m.messageHandlers[method] = c
-
    return nil
 }

@@ -58,7 +59,6 @@ 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
 }
@@ -76,7 +76,7 @@ func (m *methods) callLoopEvent(c *Channel, event string) {
        return
    }

-   f.callFunc(c, &struct{}{})
+   f.callFunc(c, nil)
 }

 /**
@@ -94,13 +94,14 @@ func (m *methods) processIncomingMessage(c *Channel, msg *protocol.Message) {
        }

        if !f.ArgsPresent {
-           f.callFunc(c, &struct{}{})
+           f.callFunc(c, nil)
            return
        }

        data := f.getArgs()
-       err := json.Unmarshal([]byte(msg.Args), &data)
+       err := json.Unmarshal([]byte("["+msg.Args+"]"), &data)
        if err != nil {
+           fmt.Printf("Error processing message. msg.Args: %v, data: %v, err: %v\n", msg.Args, data, err)
            return
        }

@@ -120,10 +121,9 @@ func (m *methods) processIncomingMessage(c *Channel, msg *protocol.Message) {
            if err != nil {
                return
            }
-
            result = f.callFunc(c, data)
        } else {
-           result = f.callFunc(c, &struct{}{})
+           result = f.callFunc(c, nil)
        }

        ack := &protocol.Message{
diff --git a/send.go b/send.go
index 07e8130..386a196 100644
--- a/send.go
+++ b/send.go
@@ -3,9 +3,10 @@ package gosocketio
 import (
    "encoding/json"
    "errors"
-   "github.com/graarh/golang-socketio/protocol"
    "log"
    "time"
+
+   "github.com/graarh/golang-socketio/protocol"
 )

 var (
@@ -32,7 +33,6 @@ func send(msg *protocol.Message, c *Channel, args interface{}) error {

        msg.Args = string(json)
    }
-
    command, err := protocol.Encode(msg)
    if err != nil {
        return err
rof20004 commented 3 years ago

how you solved this issue?