...

Source file src/net/rpc/jsonrpc/client.go

     1	// Copyright 2010 The Go Authors. 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 jsonrpc implements a JSON-RPC 1.0 ClientCodec and ServerCodec
     6	// for the rpc package.
     7	// For JSON-RPC 2.0 support, see https://godoc.org/?q=json-rpc+2.0
     8	package jsonrpc
     9	
    10	import (
    11		"encoding/json"
    12		"fmt"
    13		"io"
    14		"net"
    15		"net/rpc"
    16		"sync"
    17	)
    18	
    19	type clientCodec struct {
    20		dec *json.Decoder // for reading JSON values
    21		enc *json.Encoder // for writing JSON values
    22		c   io.Closer
    23	
    24		// temporary work space
    25		req  clientRequest
    26		resp clientResponse
    27	
    28		// JSON-RPC responses include the request id but not the request method.
    29		// Package rpc expects both.
    30		// We save the request method in pending when sending a request
    31		// and then look it up by request ID when filling out the rpc Response.
    32		mutex   sync.Mutex        // protects pending
    33		pending map[uint64]string // map request id to method name
    34	}
    35	
    36	// NewClientCodec returns a new rpc.ClientCodec using JSON-RPC on conn.
    37	func NewClientCodec(conn io.ReadWriteCloser) rpc.ClientCodec {
    38		return &clientCodec{
    39			dec:     json.NewDecoder(conn),
    40			enc:     json.NewEncoder(conn),
    41			c:       conn,
    42			pending: make(map[uint64]string),
    43		}
    44	}
    45	
    46	type clientRequest struct {
    47		Method string         `json:"method"`
    48		Params [1]interface{} `json:"params"`
    49		Id     uint64         `json:"id"`
    50	}
    51	
    52	func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) error {
    53		c.mutex.Lock()
    54		c.pending[r.Seq] = r.ServiceMethod
    55		c.mutex.Unlock()
    56		c.req.Method = r.ServiceMethod
    57		c.req.Params[0] = param
    58		c.req.Id = r.Seq
    59		return c.enc.Encode(&c.req)
    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	func (r *clientResponse) reset() {
    69		r.Id = 0
    70		r.Result = nil
    71		r.Error = nil
    72	}
    73	
    74	func (c *clientCodec) ReadResponseHeader(r *rpc.Response) error {
    75		c.resp.reset()
    76		if err := c.dec.Decode(&c.resp); err != nil {
    77			return err
    78		}
    79	
    80		c.mutex.Lock()
    81		r.ServiceMethod = c.pending[c.resp.Id]
    82		delete(c.pending, c.resp.Id)
    83		c.mutex.Unlock()
    84	
    85		r.Error = ""
    86		r.Seq = c.resp.Id
    87		if c.resp.Error != nil || c.resp.Result == nil {
    88			x, ok := c.resp.Error.(string)
    89			if !ok {
    90				return fmt.Errorf("invalid error %v", c.resp.Error)
    91			}
    92			if x == "" {
    93				x = "unspecified error"
    94			}
    95			r.Error = x
    96		}
    97		return nil
    98	}
    99	
   100	func (c *clientCodec) ReadResponseBody(x interface{}) error {
   101		if x == nil {
   102			return nil
   103		}
   104		return json.Unmarshal(*c.resp.Result, x)
   105	}
   106	
   107	func (c *clientCodec) Close() error {
   108		return c.c.Close()
   109	}
   110	
   111	// NewClient returns a new rpc.Client to handle requests to the
   112	// set of services at the other end of the connection.
   113	func NewClient(conn io.ReadWriteCloser) *rpc.Client {
   114		return rpc.NewClientWithCodec(NewClientCodec(conn))
   115	}
   116	
   117	// Dial connects to a JSON-RPC server at the specified network address.
   118	func Dial(network, address string) (*rpc.Client, error) {
   119		conn, err := net.Dial(network, address)
   120		if err != nil {
   121			return nil, err
   122		}
   123		return NewClient(conn), err
   124	}
   125	

View as plain text