...

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

Documentation: net/rpc/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  

View as plain text