libgo: update to go1.9
[official-gcc.git] / libgo / go / net / rpc / jsonrpc / client.go
blobe6359bed5985cf02f899103f842a5bfa6f7e90dc
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.
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
10 import (
11 "encoding/json"
12 "fmt"
13 "io"
14 "net"
15 "net/rpc"
16 "sync"
19 type clientCodec struct {
20 dec *json.Decoder // for reading JSON values
21 enc *json.Encoder // for writing JSON values
22 c io.Closer
24 // temporary work space
25 req clientRequest
26 resp clientResponse
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
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),
46 type clientRequest struct {
47 Method string `json:"method"`
48 Params [1]interface{} `json:"params"`
49 Id uint64 `json:"id"`
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)
62 type clientResponse struct {
63 Id uint64 `json:"id"`
64 Result *json.RawMessage `json:"result"`
65 Error interface{} `json:"error"`
68 func (r *clientResponse) reset() {
69 r.Id = 0
70 r.Result = nil
71 r.Error = nil
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
80 c.mutex.Lock()
81 r.ServiceMethod = c.pending[c.resp.Id]
82 delete(c.pending, c.resp.Id)
83 c.mutex.Unlock()
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)
92 if x == "" {
93 x = "unspecified error"
95 r.Error = x
97 return nil
100 func (c *clientCodec) ReadResponseBody(x interface{}) error {
101 if x == nil {
102 return nil
104 return json.Unmarshal(*c.resp.Result, x)
107 func (c *clientCodec) Close() error {
108 return c.c.Close()
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))
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
123 return NewClient(conn), err