github.com/btccom/go-micro/v2@v2.9.3/codec/jsonrpc/client.go (about)

     1  package jsonrpc
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"sync"
     8  
     9  	"github.com/btccom/go-micro/v2/codec"
    10  )
    11  
    12  type clientCodec struct {
    13  	dec *json.Decoder // for reading JSON values
    14  	enc *json.Encoder // for writing JSON values
    15  	c   io.Closer
    16  
    17  	// temporary work space
    18  	req  clientRequest
    19  	resp clientResponse
    20  
    21  	sync.Mutex
    22  	pending map[interface{}]string
    23  }
    24  
    25  type clientRequest struct {
    26  	Method string         `json:"method"`
    27  	Params [1]interface{} `json:"params"`
    28  	ID     interface{}    `json:"id"`
    29  }
    30  
    31  type clientResponse struct {
    32  	ID     interface{}      `json:"id"`
    33  	Result *json.RawMessage `json:"result"`
    34  	Error  interface{}      `json:"error"`
    35  }
    36  
    37  func newClientCodec(conn io.ReadWriteCloser) *clientCodec {
    38  	return &clientCodec{
    39  		dec:     json.NewDecoder(conn),
    40  		enc:     json.NewEncoder(conn),
    41  		c:       conn,
    42  		pending: make(map[interface{}]string),
    43  	}
    44  }
    45  
    46  func (c *clientCodec) Write(m *codec.Message, b interface{}) error {
    47  	c.Lock()
    48  	c.pending[m.Id] = m.Method
    49  	c.Unlock()
    50  	c.req.Method = m.Method
    51  	c.req.Params[0] = b
    52  	c.req.ID = m.Id
    53  	return c.enc.Encode(&c.req)
    54  }
    55  
    56  func (r *clientResponse) reset() {
    57  	r.ID = 0
    58  	r.Result = nil
    59  	r.Error = nil
    60  }
    61  
    62  func (c *clientCodec) ReadHeader(m *codec.Message) error {
    63  	c.resp.reset()
    64  	if err := c.dec.Decode(&c.resp); err != nil {
    65  		return err
    66  	}
    67  
    68  	c.Lock()
    69  	m.Method = c.pending[c.resp.ID]
    70  	delete(c.pending, c.resp.ID)
    71  	c.Unlock()
    72  
    73  	m.Error = ""
    74  	m.Id = fmt.Sprintf("%v", c.resp.ID)
    75  	if c.resp.Error != nil {
    76  		x, ok := c.resp.Error.(string)
    77  		if !ok {
    78  			return fmt.Errorf("invalid error %v", c.resp.Error)
    79  		}
    80  		if x == "" {
    81  			x = "unspecified error"
    82  		}
    83  		m.Error = x
    84  	}
    85  	return nil
    86  }
    87  
    88  func (c *clientCodec) ReadBody(x interface{}) error {
    89  	if x == nil || c.resp.Result == nil {
    90  		return nil
    91  	}
    92  	return json.Unmarshal(*c.resp.Result, x)
    93  }
    94  
    95  func (c *clientCodec) Close() error {
    96  	return c.c.Close()
    97  }