From ff90224ba8166ebb2df545af44f3f832ac3452c5 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 9 Mar 2017 18:30:55 +0400 Subject: [PATCH] fix "Expected map but got type string" error Error from tendermint: ``` panic: Expected map but got type string [recovered] panic: Expected map but got type string goroutine 82 [running]: testing.tRunner.func1(0xc420464000) /usr/local/go/src/testing/testing.go:622 +0x29d panic(0xa1fda0, 0xc4201eecd0) /usr/local/go/src/runtime/panic.go:489 +0x2cf github.com/tendermint/tendermint/rpc/test.waitForEvent(0xc420464000, 0xc420064000, 0xae6fae, 0x8, 0xae6f01, 0xc2e998, 0xc2e9a0) /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/test/helpers.go:179 +0x53a github.com/tendermint/tendermint/rpc/test.TestWSNewBlock(0xc420464000) /home/vagrant/go/src/github.com/tendermint/tendermint/rpc/test/client_test.go:190 +0x12e testing.tRunner(0xc420464000, 0xc2e9a8) /usr/local/go/src/testing/testing.go:657 +0x96 created by testing.(*T).Run /usr/local/go/src/testing/testing.go:697 +0x2ca ``` --- rpc_test.go | 47 ++++++++++++++++++++++++++++++++++++++++++++-- server/handlers.go | 17 +++++++++++------ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/rpc_test.go b/rpc_test.go index 074c212a8..334909f1f 100644 --- a/rpc_test.go +++ b/rpc_test.go @@ -44,8 +44,9 @@ var _ = wire.RegisterInterface( // Define some routes var Routes = map[string]*server.RPCFunc{ - "status": server.NewRPCFunc(StatusResult, "arg"), - "bytes": server.NewRPCFunc(BytesResult, "arg"), + "status": server.NewRPCFunc(StatusResult, "arg"), + "status_ws": server.NewWSRPCFunc(StatusWSResult, "arg"), + "bytes": server.NewRPCFunc(BytesResult, "arg"), } // an rpc function @@ -53,6 +54,10 @@ func StatusResult(v string) (Result, error) { return &ResultStatus{v}, nil } +func StatusWSResult(wsCtx types.WSRPCContext, v string) (Result, error) { + return &ResultStatus{v}, nil +} + func BytesResult(v []byte) (Result, error) { return &ResultBytes{v}, nil } @@ -259,3 +264,41 @@ func TestByteSliceViaJSONRPC(t *testing.T) { t.Fatalf("Got: %v .... Expected: %v \n", got, val) } } + +func TestWSNewWSRPCFunc(t *testing.T) { + cl := client.NewWSClient(unixAddr, websocketEndpoint) + _, err := cl.Start() + if err != nil { + t.Fatal(err) + } + defer cl.Stop() + + val := "acbd" + params := map[string]interface{}{ + "arg": val, + } + err = cl.WriteJSON(types.RPCRequest{ + JSONRPC: "2.0", + ID: "", + Method: "status_ws", + Params: params, + }) + if err != nil { + t.Fatal(err) + } + + select { + case msg := <-cl.ResultsCh: + result := new(Result) + wire.ReadJSONPtr(result, msg, &err) + if err != nil { + t.Fatal(err) + } + got := (*result).(*ResultStatus).Value + if got != val { + t.Fatalf("Got: %v .... Expected: %v \n", got, val) + } + case err := <-cl.ErrorsCh: + t.Fatal(err) + } +} diff --git a/server/handlers.go b/server/handlers.go index 6e746a26b..e590a45fd 100644 --- a/server/handlers.go +++ b/server/handlers.go @@ -123,7 +123,7 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc { WriteRPCResponseHTTP(w, types.NewRPCResponse(request.ID, nil, "RPC method is only for websockets: "+request.Method)) return } - args, err := jsonParamsToArgs(rpcFunc, request.Params) + args, err := jsonParamsToArgs(rpcFunc, request.Params, 0) if err != nil { WriteRPCResponseHTTP(w, types.NewRPCResponse(request.ID, nil, fmt.Sprintf("Error converting json params to arguments: %v", err.Error()))) return @@ -140,11 +140,16 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc { } // Convert a list of interfaces to properly typed values -func jsonParamsToArgs(rpcFunc *RPCFunc, params map[string]interface{}) ([]reflect.Value, error) { - values := make([]reflect.Value, len(rpcFunc.args)) +// +// argsOffset is used in jsonParamsToArgsWS, where len(rpcFunc.args) != len(rpcFunc.argNames). +// Example: +// rpcFunc.args = [rpctypes.WSRPCContext string] +// rpcFunc.argNames = ["arg"] +func jsonParamsToArgs(rpcFunc *RPCFunc, params map[string]interface{}, argsOffset int) ([]reflect.Value, error) { + values := make([]reflect.Value, len(rpcFunc.argNames)) for i, argName := range rpcFunc.argNames { - argType := rpcFunc.args[i] + argType := rpcFunc.args[i+argsOffset] // decode param if provided if param, ok := params[argName]; ok && "" != param { @@ -163,7 +168,7 @@ func jsonParamsToArgs(rpcFunc *RPCFunc, params map[string]interface{}) ([]reflec // Same as above, but with the first param the websocket connection func jsonParamsToArgsWS(rpcFunc *RPCFunc, params map[string]interface{}, wsCtx types.WSRPCContext) ([]reflect.Value, error) { - values, err := jsonParamsToArgs(rpcFunc, params) + values, err := jsonParamsToArgs(rpcFunc, params, 1) if err != nil { return nil, err } @@ -463,7 +468,7 @@ func (wsc *wsConnection) readRoutine() { wsCtx := types.WSRPCContext{Request: request, WSRPCConnection: wsc} args, err = jsonParamsToArgsWS(rpcFunc, request.Params, wsCtx) } else { - args, err = jsonParamsToArgs(rpcFunc, request.Params) + args, err = jsonParamsToArgs(rpcFunc, request.Params, 0) } if err != nil { wsc.WriteRPCResponse(types.NewRPCResponse(request.ID, nil, err.Error()))