github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/rpc/lib/jsonrpc/client.go (about)

     1  package jsonrpc
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/url"
    10  	"reflect"
    11  
    12  	"github.com/hyperledger/burrow/rpc/lib/types"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // HTTPClient is a common interface for Client and URIClient.
    17  type HTTPClient interface {
    18  	Call(method string, params interface{}, result interface{}) error
    19  }
    20  
    21  // Client takes params as a slice
    22  type Client struct {
    23  	address string
    24  	client  http.Client
    25  }
    26  
    27  // NewClient returns a Client pointed at the given address.
    28  func NewClient(remote string) *Client {
    29  	return &Client{
    30  		address: remote,
    31  	}
    32  }
    33  
    34  func (c *Client) Call(method string, params interface{}, result interface{}) error {
    35  	request, err := types.NewRequest("jsonrpc-client", method, params)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	bs, err := json.Marshal(request)
    40  	if err != nil {
    41  		return err
    42  	}
    43  	buf := bytes.NewBuffer(bs)
    44  	response, err := c.client.Post(c.address, "application/json", buf)
    45  	if err != nil {
    46  		return err
    47  	}
    48  	defer response.Body.Close()
    49  
    50  	bs, err = ioutil.ReadAll(response.Body)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	return unmarshalResponseBytes(bs, result)
    55  }
    56  
    57  // URI takes params as a map
    58  type URIClient struct {
    59  	address string
    60  	client  http.Client
    61  }
    62  
    63  func NewURIClient(remote string) *URIClient {
    64  	return &URIClient{
    65  		address: remote,
    66  	}
    67  }
    68  
    69  func (c *URIClient) Call(method string, params interface{}, result interface{}) error {
    70  	values, err := argsToURLValues(params.(map[string]interface{}))
    71  	if err != nil {
    72  		return err
    73  	}
    74  	// log.Info(Fmt("URI request to %v (%v): %v", c.address, method, values))
    75  	resp, err := c.client.PostForm(c.address+"/"+method, values)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	defer resp.Body.Close() // nolint: errcheck
    80  
    81  	responseBytes, err := ioutil.ReadAll(resp.Body)
    82  	if err != nil {
    83  		return err
    84  	}
    85  	return unmarshalResponseBytes(responseBytes, result)
    86  }
    87  
    88  func unmarshalResponseBytes(responseBytes []byte, result interface{}) error {
    89  	var err error
    90  	response := &types.RPCResponse{}
    91  	err = json.Unmarshal(responseBytes, response)
    92  	if err != nil {
    93  		return errors.Errorf("Error unmarshalling rpc response: %v", err)
    94  	}
    95  	if response.Error != nil {
    96  		return response.Error
    97  	}
    98  	// Unmarshal the RawMessage into the result.
    99  	err = json.Unmarshal(response.Result, result)
   100  	if err != nil {
   101  		return errors.Errorf("error unmarshalling rpc response result: %v", err)
   102  	}
   103  	return nil
   104  }
   105  
   106  func argsToURLValues(args map[string]interface{}) (url.Values, error) {
   107  	values := make(url.Values)
   108  	if len(args) == 0 {
   109  		return values, nil
   110  	}
   111  	err := argsToJSON(args)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	for key, val := range args {
   116  		values.Set(key, val.(string))
   117  	}
   118  	return values, nil
   119  }
   120  
   121  func argsToJSON(args map[string]interface{}) error {
   122  	for k, v := range args {
   123  		rt := reflect.TypeOf(v)
   124  		isByteSlice := rt.Kind() == reflect.Slice && rt.Elem().Kind() == reflect.Uint8
   125  		if isByteSlice {
   126  			bs := reflect.ValueOf(v).Bytes()
   127  			args[k] = fmt.Sprintf("0x%X", bs)
   128  			continue
   129  		}
   130  
   131  		data, err := json.Marshal(v)
   132  		if err != nil {
   133  			return err
   134  		}
   135  		args[k] = string(data)
   136  	}
   137  	return nil
   138  }