json.RawMessage in RPCRequest to defer parsing
This commit is contained in:
parent
6dbcfb32d2
commit
6ba799132c
|
@ -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{
|
request, err := types.MapToRequest("", method, params)
|
||||||
JSONRPC: "2.0",
|
if err != nil {
|
||||||
Method: method,
|
return nil, err
|
||||||
Params: params,
|
|
||||||
ID: "",
|
|
||||||
}
|
}
|
||||||
requestBytes, err := json.Marshal(request)
|
requestBytes, err := json.Marshal(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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{
|
params := map[string]interface{}{"event": eventid}
|
||||||
JSONRPC: "2.0",
|
request, err := types.MapToRequest("", "subscribe", params)
|
||||||
ID: "",
|
if err == nil {
|
||||||
Method: "subscribe",
|
err = wsc.WriteJSON(request)
|
||||||
Params: map[string]interface{}{"event": eventid},
|
}
|
||||||
})
|
|
||||||
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{
|
params := map[string]interface{}{"event": eventid}
|
||||||
JSONRPC: "2.0",
|
request, err := types.MapToRequest("", "unsubscribe", params)
|
||||||
ID: "",
|
if err == nil {
|
||||||
Method: "unsubscribe",
|
err = wsc.WriteJSON(request)
|
||||||
Params: map[string]interface{}{"event": eventid},
|
}
|
||||||
})
|
|
||||||
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{
|
request, err := types.MapToRequest("", method, params)
|
||||||
JSONRPC: "2.0",
|
if err == nil {
|
||||||
Method: method,
|
err = wsc.WriteJSON(request)
|
||||||
Params: params,
|
}
|
||||||
ID: "",
|
|
||||||
})
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,12 +306,9 @@ func TestWSHandlesArrayParams(t *testing.T) {
|
||||||
|
|
||||||
val := "acbd"
|
val := "acbd"
|
||||||
params := []interface{}{val}
|
params := []interface{}{val}
|
||||||
err = cl.WriteJSON(types.RPCRequest{
|
request, err := types.ArrayToRequest("", "echo_ws", params)
|
||||||
JSONRPC: "2.0",
|
require.Nil(t, err)
|
||||||
ID: "",
|
err = cl.WriteJSON(request)
|
||||||
Method: "echo_ws",
|
|
||||||
Params: params,
|
|
||||||
})
|
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|
|
@ -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, ¶msI)
|
||||||
|
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) {
|
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, params *json.RawMessage) ([]reflect.Value, error) {
|
||||||
return jsonParamsToArgs(rpcFunc, paramsI, 0)
|
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) {
|
func jsonParamsToArgsWS(rpcFunc *RPCFunc, params *json.RawMessage, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
|
||||||
values, err := jsonParamsToArgs(rpcFunc, paramsI, 1)
|
values, err := jsonParamsToArgs(rpcFunc, *params, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,39 @@ 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 interface{} `json:"params"` // must be map[string]interface{} or []interface{}
|
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: ¶ms,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
type RPCResponse struct {
|
type RPCResponse struct {
|
||||||
|
|
Loading…
Reference in New Issue