github.com/turingchain2020/turingchain@v1.1.21/rpc/jsonclient/jsonclient.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package jsonclient 实现JSON rpc客户端请求功能
     6  package jsonclient
     7  
     8  import (
     9  	"bytes"
    10  	"crypto/tls"
    11  	"encoding/json"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"net/http"
    15  	"strings"
    16  
    17  	"github.com/turingchain2020/turingchain/types"
    18  	"github.com/golang/protobuf/proto"
    19  )
    20  
    21  // JSONClient a object of jsonclient
    22  type JSONClient struct {
    23  	url       string
    24  	prefix    string
    25  	tlsVerify bool
    26  	client    *http.Client
    27  }
    28  
    29  func addPrefix(prefix, name string) string {
    30  	if strings.Contains(name, ".") {
    31  		return name
    32  	}
    33  	return prefix + "." + name
    34  }
    35  
    36  // NewJSONClient produce a json object
    37  func NewJSONClient(url string) (*JSONClient, error) {
    38  	return New("Turingchain", url, false)
    39  }
    40  
    41  // New produce a jsonclient by perfix and url
    42  func New(prefix, url string, tlsVerify bool) (*JSONClient, error) {
    43  	httpcli := http.DefaultClient
    44  	if strings.Contains(url, "https") { //暂不校验tls证书
    45  		/* #nosec */
    46  		httpcli = &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: !tlsVerify}}}
    47  	}
    48  	return &JSONClient{
    49  		url:       url,
    50  		prefix:    prefix,
    51  		tlsVerify: tlsVerify,
    52  		client:    httpcli,
    53  	}, nil
    54  }
    55  
    56  type clientRequest struct {
    57  	Method string         `json:"method"`
    58  	Params [1]interface{} `json:"params"`
    59  	ID     uint64         `json:"id"`
    60  }
    61  
    62  type clientResponse struct {
    63  	ID     uint64           `json:"id"`
    64  	Result *json.RawMessage `json:"result"`
    65  	Error  interface{}      `json:"error"`
    66  }
    67  
    68  // Call jsonclinet call method
    69  func (client *JSONClient) Call(method string, params, resp interface{}) error {
    70  	method = addPrefix(client.prefix, method)
    71  	req := &clientRequest{}
    72  	req.Method = method
    73  	req.Params[0] = params
    74  	data, err := json.Marshal(req)
    75  	if err != nil {
    76  		return err
    77  	}
    78  	//println("request JsonStr", string(data), "")
    79  	postresp, err := client.client.Post(client.url, "application/json", bytes.NewBuffer(data))
    80  	if err != nil {
    81  		return err
    82  	}
    83  	defer postresp.Body.Close()
    84  	b, err := ioutil.ReadAll(postresp.Body)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	//println("response", string(b), "")
    89  	cresp := &clientResponse{}
    90  	err = json.Unmarshal(b, &cresp)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	if cresp.Error != nil /*|| cresp.Result == nil*/ {
    95  		x, ok := cresp.Error.(string)
    96  		if !ok {
    97  			return fmt.Errorf("invalid error %v", cresp.Error)
    98  		}
    99  		if x == "" {
   100  			x = "unspecified error"
   101  		}
   102  		return fmt.Errorf(x)
   103  	}
   104  	if cresp.Result == nil {
   105  		return types.ErrEmpty
   106  	}
   107  	if msg, ok := resp.(proto.Message); ok {
   108  		var str json.RawMessage
   109  		err = json.Unmarshal(*cresp.Result, &str)
   110  		if err != nil {
   111  			return err
   112  		}
   113  		b, err := str.MarshalJSON()
   114  		if err != nil {
   115  			return err
   116  		}
   117  		return types.JSONToPB(b, msg)
   118  	}
   119  	return json.Unmarshal(*cresp.Result, resp)
   120  }