RPCRequest.Params can be map[string]interface{} or []interface{}

This commit is contained in:
Ethan Buchman 2017-04-12 13:42:19 -04:00
parent 9d18cbe74e
commit c3295f4878
2 changed files with 36 additions and 16 deletions

View File

@ -140,36 +140,56 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc {
} }
} }
// Convert a list of interfaces to properly typed values // Convert a []interface{} OR a map[string]interface{} to properly typed values
// //
// argsOffset is used in jsonParamsToArgsWS, where len(rpcFunc.args) != len(rpcFunc.argNames). // argsOffset is used in jsonParamsToArgsWS, where len(rpcFunc.args) != len(rpcFunc.argNames).
// Example: // Example:
// rpcFunc.args = [rpctypes.WSRPCContext string] // rpcFunc.args = [rpctypes.WSRPCContext string]
// rpcFunc.argNames = ["arg"] // rpcFunc.argNames = ["arg"]
func jsonParamsToArgs(rpcFunc *RPCFunc, params map[string]interface{}, argsOffset int) ([]reflect.Value, error) { func jsonParamsToArgs(rpcFunc *RPCFunc, paramsI interface{}, argsOffset int) ([]reflect.Value, error) {
values := make([]reflect.Value, len(rpcFunc.argNames)) values := make([]reflect.Value, len(rpcFunc.argNames))
for i, argName := range rpcFunc.argNames { switch params := paramsI.(type) {
argType := rpcFunc.args[i+argsOffset]
// decode param if provided case map[string]interface{}:
if param, ok := params[argName]; ok && "" != param { for i, argName := range rpcFunc.argNames {
v, err := _jsonObjectToArg(argType, param) argType := rpcFunc.args[i+argsOffset]
// decode param if provided
if param, ok := params[argName]; ok && "" != param {
v, err := _jsonObjectToArg(argType, param)
if err != nil {
return nil, err
}
values[i] = v
} else { // use default for that type
values[i] = reflect.Zero(argType)
}
}
case []interface{}:
if len(rpcFunc.argNames) != len(params) {
return nil, errors.New(fmt.Sprintf("Expected %v parameters (%v), got %v (%v)",
len(rpcFunc.argNames), rpcFunc.argNames, len(params), params))
}
values := make([]reflect.Value, len(params))
for i, p := range params {
ty := rpcFunc.args[i]
v, err := _jsonObjectToArg(ty, p)
if err != nil { if err != nil {
return nil, err return nil, err
} }
values[i] = v values[i] = v
} else { // use default for that type
values[i] = reflect.Zero(argType)
} }
return values, nil
default:
return nil, fmt.Errorf("Unknown type for JSON params %v. Expected map[string]interface{} or []interface{}", reflect.TypeOf(paramsI))
} }
return values, nil return values, nil
} }
// Same as above, but with the first param the websocket connection // 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) { func jsonParamsToArgsWS(rpcFunc *RPCFunc, paramsI interface{}, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
values, err := jsonParamsToArgs(rpcFunc, params, 1) values, err := jsonParamsToArgs(rpcFunc, paramsI, 1)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -9,10 +9,10 @@ import (
) )
type RPCRequest struct { type RPCRequest struct {
JSONRPC string `json:"jsonrpc"` JSONRPC string `json:"jsonrpc"`
ID string `json:"id"` ID string `json:"id"`
Method string `json:"method"` Method string `json:"method"`
Params map[string]interface{} `json:"params"` Params interface{} `json:"params"` // must be map[string]interface{} or []interface{}
} }
func NewRPCRequest(id string, method string, params map[string]interface{}) RPCRequest { func NewRPCRequest(id string, method string, params map[string]interface{}) RPCRequest {