go-micro.dev/v5@v5.12.0/codec/jsonrpc/client.go (about)

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