-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmessage.go
358 lines (299 loc) · 8.35 KB
/
message.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
// SPDX-FileCopyrightText: 2021 The Go Language Server Authors
// SPDX-License-Identifier: BSD-3-Clause
package jsonrpc2
import (
"bytes"
"errors"
"fmt"
"github.com/segmentio/encoding/json"
)
// Message is the interface to all JSON-RPC message types.
//
// They share no common functionality, but are a closed set of concrete types
// that are allowed to implement this interface.
//
// The message types are *Call, *Response and *Notification.
type Message interface {
// jsonrpc2Message is used to make the set of message implementations a
// closed set.
jsonrpc2Message()
}
// Request is the shared interface to jsonrpc2 messages that request
// a method be invoked.
//
// The request types are a closed set of *Call and *Notification.
type Request interface {
Message
// Method is a string containing the method name to invoke.
Method() string
// Params is either a struct or an array with the parameters of the method.
Params() json.RawMessage
// jsonrpc2Request is used to make the set of request implementations closed.
jsonrpc2Request()
}
// Call is a request that expects a response.
//
// The response will have a matching ID.
type Call struct {
// Method is a string containing the method name to invoke.
method string
// Params is either a struct or an array with the parameters of the method.
params json.RawMessage
// id of this request, used to tie the Response back to the request.
id ID
}
// make sure a Call implements the Request, json.Marshaler and json.Unmarshaler and interfaces.
var (
_ Request = (*Call)(nil)
_ json.Marshaler = (*Call)(nil)
_ json.Unmarshaler = (*Call)(nil)
)
// NewCall constructs a new Call message for the supplied ID, method and
// parameters.
func NewCall(id ID, method string, params interface{}) (*Call, error) {
p, merr := marshalInterface(params)
req := &Call{
id: id,
method: method,
params: p,
}
return req, merr
}
// ID returns the current call id.
func (c *Call) ID() ID { return c.id }
// Method implements Request.
func (c *Call) Method() string { return c.method }
// Params implements Request.
func (c *Call) Params() json.RawMessage { return c.params }
// jsonrpc2Message implements Request.
func (Call) jsonrpc2Message() {}
// jsonrpc2Request implements Request.
func (Call) jsonrpc2Request() {}
// MarshalJSON implements json.Marshaler.
func (c Call) MarshalJSON() ([]byte, error) {
req := wireRequest{
Method: c.method,
Params: &c.params,
ID: &c.id,
}
data, err := json.Marshal(req)
if err != nil {
return data, fmt.Errorf("marshaling call: %w", err)
}
return data, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (c *Call) UnmarshalJSON(data []byte) error {
var req wireRequest
dec := json.NewDecoder(bytes.NewReader(data))
dec.ZeroCopy()
if err := dec.Decode(&req); err != nil {
return fmt.Errorf("unmarshaling call: %w", err)
}
c.method = req.Method
if req.Params != nil {
c.params = *req.Params
}
if req.ID != nil {
c.id = *req.ID
}
return nil
}
// Response is a reply to a Request.
//
// It will have the same ID as the call it is a response to.
type Response struct {
// result is the content of the response.
result json.RawMessage
// err is set only if the call failed.
err error
// ID of the request this is a response to.
id ID
}
// make sure a Response implements the Message, json.Marshaler and json.Unmarshaler and interfaces.
var (
_ Message = (*Response)(nil)
_ json.Marshaler = (*Response)(nil)
_ json.Unmarshaler = (*Response)(nil)
)
// NewResponse constructs a new Response message that is a reply to the
// supplied. If err is set result may be ignored.
func NewResponse(id ID, result interface{}, err error) (*Response, error) {
r, merr := marshalInterface(result)
resp := &Response{
id: id,
result: r,
err: err,
}
return resp, merr
}
// ID returns the current response id.
func (r *Response) ID() ID { return r.id }
// Result returns the Response result.
func (r *Response) Result() json.RawMessage { return r.result }
// Err returns the Response error.
func (r *Response) Err() error { return r.err }
// jsonrpc2Message implements Message.
func (r *Response) jsonrpc2Message() {}
// MarshalJSON implements json.Marshaler.
func (r Response) MarshalJSON() ([]byte, error) {
resp := &wireResponse{
Error: toError(r.err),
ID: &r.id,
}
if resp.Error == nil {
resp.Result = &r.result
}
data, err := json.Marshal(resp)
if err != nil {
return data, fmt.Errorf("marshaling notification: %w", err)
}
return data, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (r *Response) UnmarshalJSON(data []byte) error {
var resp wireResponse
dec := json.NewDecoder(bytes.NewReader(data))
dec.ZeroCopy()
if err := dec.Decode(&resp); err != nil {
return fmt.Errorf("unmarshaling jsonrpc response: %w", err)
}
if resp.Result != nil {
r.result = *resp.Result
}
if resp.Error != nil {
r.err = resp.Error
}
if resp.ID != nil {
r.id = *resp.ID
}
return nil
}
func toError(err error) *Error {
if err == nil {
// no error, the response is complete
return nil
}
var wrapped *Error
if errors.As(err, &wrapped) {
// already a wire error, just use it
return wrapped
}
result := &Error{Message: err.Error()}
if errors.As(err, &wrapped) {
// if we wrapped a wire error, keep the code from the wrapped error
// but the message from the outer error
result.Code = wrapped.Code
}
return result
}
// Notification is a request for which a response cannot occur, and as such
// it has not ID.
type Notification struct {
// Method is a string containing the method name to invoke.
method string
params json.RawMessage
}
// make sure a Notification implements the Request, json.Marshaler and json.Unmarshaler and interfaces.
var (
_ Request = (*Notification)(nil)
_ json.Marshaler = (*Notification)(nil)
_ json.Unmarshaler = (*Notification)(nil)
)
// NewNotification constructs a new Notification message for the supplied
// method and parameters.
func NewNotification(method string, params interface{}) (*Notification, error) {
p, merr := marshalInterface(params)
notify := &Notification{
method: method,
params: p,
}
return notify, merr
}
// Method implements Request.
func (n *Notification) Method() string { return n.method }
// Params implements Request.
func (n *Notification) Params() json.RawMessage { return n.params }
// jsonrpc2Message implements Request.
func (Notification) jsonrpc2Message() {}
// jsonrpc2Request implements Request.
func (Notification) jsonrpc2Request() {}
// MarshalJSON implements json.Marshaler.
func (n Notification) MarshalJSON() ([]byte, error) {
req := wireRequest{
Method: n.method,
Params: &n.params,
}
data, err := json.Marshal(req)
if err != nil {
return data, fmt.Errorf("marshaling notification: %w", err)
}
return data, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (n *Notification) UnmarshalJSON(data []byte) error {
var req wireRequest
dec := json.NewDecoder(bytes.NewReader(data))
dec.ZeroCopy()
if err := dec.Decode(&req); err != nil {
return fmt.Errorf("unmarshaling notification: %w", err)
}
n.method = req.Method
if req.Params != nil {
n.params = *req.Params
}
return nil
}
// DecodeMessage decodes data to Message.
func DecodeMessage(data []byte) (Message, error) {
var msg combined
dec := json.NewDecoder(bytes.NewReader(data))
dec.ZeroCopy()
if err := dec.Decode(&msg); err != nil {
return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err)
}
if msg.Method == "" {
// no method, should be a response
if msg.ID == nil {
return nil, ErrInvalidRequest
}
resp := &Response{
id: *msg.ID,
}
if msg.Error != nil {
resp.err = msg.Error
}
if msg.Result != nil {
resp.result = *msg.Result
}
return resp, nil
}
// has a method, must be a request
if msg.ID == nil {
// request with no ID is a notify
notify := &Notification{
method: msg.Method,
}
if msg.Params != nil {
notify.params = *msg.Params
}
return notify, nil
}
// request with an ID, must be a call
call := &Call{
method: msg.Method,
id: *msg.ID,
}
if msg.Params != nil {
call.params = *msg.Params
}
return call, nil
}
// marshalInterface marshal obj to json.RawMessage.
func marshalInterface(obj interface{}) (json.RawMessage, error) {
data, err := json.Marshal(obj)
if err != nil {
return json.RawMessage{}, fmt.Errorf("failed to marshal json: %w", err)
}
return json.RawMessage(data), nil
}