Browse Source

json.RawMessage in RPCRequest to defer parsing

pull/465/head
Ethan Frey 8 years ago
parent
commit
6ba799132c
5 changed files with 58 additions and 41 deletions
  1. +3
    -5
      rpc/lib/client/http_client.go
  2. +14
    -18
      rpc/lib/client/ws_client.go
  3. +3
    -6
      rpc/lib/rpc_test.go
  4. +14
    -6
      rpc/lib/server/handlers.go
  5. +24
    -6
      rpc/lib/types/types.go

+ 3
- 5
rpc/lib/client/http_client.go View File

@ -67,11 +67,9 @@ func NewJSONRPCClient(remote string) *JSONRPCClient {
} }
func (c *JSONRPCClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) { func (c *JSONRPCClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
request := types.RPCRequest{
JSONRPC: "2.0",
Method: method,
Params: params,
ID: "",
request, err := types.MapToRequest("", method, params)
if err != nil {
return nil, err
} }
requestBytes, err := json.Marshal(request) requestBytes, err := json.Marshal(request)
if err != nil { if err != nil {


+ 14
- 18
rpc/lib/client/ws_client.go View File

@ -130,35 +130,31 @@ func (wsc *WSClient) receiveEventsRoutine() {
// Subscribe to an event. Note the server must have a "subscribe" route // Subscribe to an event. Note the server must have a "subscribe" route
// defined. // defined.
func (wsc *WSClient) Subscribe(eventid string) error { func (wsc *WSClient) Subscribe(eventid string) error {
err := wsc.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
ID: "",
Method: "subscribe",
Params: map[string]interface{}{"event": eventid},
})
params := map[string]interface{}{"event": eventid}
request, err := types.MapToRequest("", "subscribe", params)
if err == nil {
err = wsc.WriteJSON(request)
}
return err return err
} }
// Unsubscribe from an event. Note the server must have a "unsubscribe" route // Unsubscribe from an event. Note the server must have a "unsubscribe" route
// defined. // defined.
func (wsc *WSClient) Unsubscribe(eventid string) error { func (wsc *WSClient) Unsubscribe(eventid string) error {
err := wsc.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
ID: "",
Method: "unsubscribe",
Params: map[string]interface{}{"event": eventid},
})
params := map[string]interface{}{"event": eventid}
request, err := types.MapToRequest("", "unsubscribe", params)
if err == nil {
err = wsc.WriteJSON(request)
}
return err return err
} }
// Call asynchronously calls a given method by sending an RPCRequest to the // Call asynchronously calls a given method by sending an RPCRequest to the
// server. Results will be available on ResultsCh, errors, if any, on ErrorsCh. // server. Results will be available on ResultsCh, errors, if any, on ErrorsCh.
func (wsc *WSClient) Call(method string, params map[string]interface{}) error { func (wsc *WSClient) Call(method string, params map[string]interface{}) error {
err := wsc.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
Method: method,
Params: params,
ID: "",
})
request, err := types.MapToRequest("", method, params)
if err == nil {
err = wsc.WriteJSON(request)
}
return err return err
} }

+ 3
- 6
rpc/lib/rpc_test.go View File

@ -306,12 +306,9 @@ func TestWSHandlesArrayParams(t *testing.T) {
val := "acbd" val := "acbd"
params := []interface{}{val} params := []interface{}{val}
err = cl.WriteJSON(types.RPCRequest{
JSONRPC: "2.0",
ID: "",
Method: "echo_ws",
Params: params,
})
request, err := types.ArrayToRequest("", "echo_ws", params)
require.Nil(t, err)
err = cl.WriteJSON(request)
require.Nil(t, err) require.Nil(t, err)
select { select {


+ 14
- 6
rpc/lib/server/handlers.go View File

@ -140,15 +140,23 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc {
} }
} }
// Convert a []interface{} OR a map[string]interface{} to properly typed values
// raw is unparsed json (from json.RawMessage). It either has
// and array or a map behind it, let's parse this all without resorting to wire...
// //
// argsOffset should be 0 for RPC calls, and 1 for WS requests, where len(rpcFunc.args) != len(rpcFunc.argNames). // argsOffset should be 0 for RPC calls, and 1 for WS requests, 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, paramsI interface{}, argsOffset int) ([]reflect.Value, error) {
func jsonParamsToArgs(rpcFunc *RPCFunc, raw []byte, argsOffset int) ([]reflect.Value, error) {
values := make([]reflect.Value, len(rpcFunc.argNames)) values := make([]reflect.Value, len(rpcFunc.argNames))
// right now, this is the same as before, but the whole parsing is in one function...
var paramsI interface{}
err := json.Unmarshal(raw, &paramsI)
if err != nil {
return nil, err
}
switch params := paramsI.(type) { switch params := paramsI.(type) {
case map[string]interface{}: case map[string]interface{}:
@ -188,13 +196,13 @@ func jsonParamsToArgs(rpcFunc *RPCFunc, paramsI interface{}, argsOffset int) ([]
} }
// Convert a []interface{} OR a map[string]interface{} to properly typed values // Convert a []interface{} OR a map[string]interface{} to properly typed values
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, paramsI interface{}) ([]reflect.Value, error) {
return jsonParamsToArgs(rpcFunc, paramsI, 0)
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, params *json.RawMessage) ([]reflect.Value, error) {
return jsonParamsToArgs(rpcFunc, *params, 0)
} }
// 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, paramsI interface{}, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
values, err := jsonParamsToArgs(rpcFunc, paramsI, 1)
func jsonParamsToArgsWS(rpcFunc *RPCFunc, params *json.RawMessage, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
values, err := jsonParamsToArgs(rpcFunc, *params, 1)
if err != nil { if err != nil {
return nil, err return nil, err
} }


+ 24
- 6
rpc/lib/types/types.go View File

@ -8,19 +8,37 @@ import (
) )
type RPCRequest struct { type RPCRequest struct {
JSONRPC string `json:"jsonrpc"`
ID string `json:"id"`
Method string `json:"method"`
Params interface{} `json:"params"` // must be map[string]interface{} or []interface{}
JSONRPC string `json:"jsonrpc"`
ID string `json:"id"`
Method string `json:"method"`
Params *json.RawMessage `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 json.RawMessage) RPCRequest {
return RPCRequest{ return RPCRequest{
JSONRPC: "2.0", JSONRPC: "2.0",
ID: id, ID: id,
Method: method, Method: method,
Params: params,
Params: &params,
}
}
func MapToRequest(id string, method string, params map[string]interface{}) (RPCRequest, error) {
payload, err := json.Marshal(params)
if err != nil {
return RPCRequest{}, err
}
request := NewRPCRequest(id, method, payload)
return request, nil
}
func ArrayToRequest(id string, method string, params []interface{}) (RPCRequest, error) {
payload, err := json.Marshal(params)
if err != nil {
return RPCRequest{}, err
} }
request := NewRPCRequest(id, method, payload)
return request, nil
} }
//---------------------------------------- //----------------------------------------


Loading…
Cancel
Save