-
Notifications
You must be signed in to change notification settings - Fork 19
/
server_util_test.go
138 lines (120 loc) · 3.36 KB
/
server_util_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// This code is all of https://golang.org/src/net/rpc/jsonrpc/server.go and some of
// https://golang.org/src/net/rpc/jsonrpc/client.go (both adjusted to use the fork).
//
// Unfortunately but logically the net/rpc/jsonrpc uses net/rpc types which are
// incompatible with this fork, so the code could not be used as-is.
//
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
package rpc
import (
"encoding/json"
"errors"
"io"
"sync"
)
var errMissingParams = errors.New("jsonrpc: request body missing params")
type jsonServerCodec struct {
dec *json.Decoder // for reading JSON values
enc *json.Encoder // for writing JSON values
c io.Closer
// temporary work space
req jsonServerRequest
// JSON-RPC clients can use arbitrary json values as request IDs.
// Package rpc expects uint64 request IDs.
// We assign uint64 sequence numbers to incoming requests
// but save the original request ID in the pending map.
// When rpc responds, we use the sequence number in
// the response to find the original request ID.
mutex sync.Mutex // protects seq, pending
seq uint64
pending map[uint64]*json.RawMessage
}
// NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn.
func NewJsonServerCodec(conn io.ReadWriteCloser) ServerCodec {
return &jsonServerCodec{
dec: json.NewDecoder(conn),
enc: json.NewEncoder(conn),
c: conn,
pending: make(map[uint64]*json.RawMessage),
}
}
type jsonServerRequest struct {
Method string `json:"method"`
Params *json.RawMessage `json:"params"`
Id *json.RawMessage `json:"id"`
}
func (r *jsonServerRequest) reset() {
r.Method = ""
r.Params = nil
r.Id = nil
}
type jsonServerResponse struct {
Id *json.RawMessage `json:"id"`
Result any `json:"result"`
Error any `json:"error"`
}
func (c *jsonServerCodec) ReadRequestHeader(r *Request) error {
c.req.reset()
if err := c.dec.Decode(&c.req); err != nil {
return err
}
r.ServiceMethod = c.req.Method
// JSON request id can be any JSON value;
// RPC package expects uint64. Translate to
// internal uint64 and save JSON on the side.
c.mutex.Lock()
c.seq++
c.pending[c.seq] = c.req.Id
c.req.Id = nil
r.Seq = c.seq
c.mutex.Unlock()
return nil
}
func (c *jsonServerCodec) ReadRequestBody(x any) error {
if x == nil {
return nil
}
if c.req.Params == nil {
return errMissingParams
}
// JSON params is array value.
// RPC params is struct.
// Unmarshal into array containing struct for now.
// Should think about making RPC more general.
var params [1]any
params[0] = x
return json.Unmarshal(*c.req.Params, ¶ms)
}
var null = json.RawMessage([]byte("null"))
func (c *jsonServerCodec) WriteResponse(r *Response, x any) error {
c.mutex.Lock()
b, ok := c.pending[r.Seq]
if !ok {
c.mutex.Unlock()
return errors.New("invalid sequence number in response")
}
delete(c.pending, r.Seq)
c.mutex.Unlock()
if b == nil {
// Invalid request so no id. Use JSON null.
b = &null
}
resp := jsonServerResponse{Id: b}
if r.Error == "" {
resp.Result = x
} else {
resp.Error = r.Error
}
return c.enc.Encode(resp)
}
func (c *jsonServerCodec) Close() error {
return c.c.Close()
}
type jsonClientRequest struct {
Method string `json:"method"`
Params [1]any `json:"params"`
Id uint64 `json:"id"`
}