1
2
3
4
5
6
7
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
21 enc *json.Encoder
22 c io.Closer
23
24
25 req clientRequest
26 resp clientResponse
27
28
29
30
31
32 mutex sync.Mutex
33 pending map[uint64]string
34 }
35
36
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]any `json:"params"`
49 Id uint64 `json:"id"`
50 }
51
52 func (c *clientCodec) WriteRequest(r *rpc.Request, param any) 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 any `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 any) 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
112
113 func NewClient(conn io.ReadWriteCloser) *rpc.Client {
114 return rpc.NewClientWithCodec(NewClientCodec(conn))
115 }
116
117
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