Home | History | Annotate | Download | only in jsonrpc
      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