1 // Copyright 2018 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.
11 errors "golang.org/x/xerrors"
14 // Message is the interface to all jsonrpc2 message types.
15 // They share no common functionality, but are a closed set of concrete types
16 // that are allowed to implement this interface. The message types are *Call,
17 // *Notification and *Response.
18 type Message interface {
19 // isJSONRPC2Message is used to make the set of message implementations a
24 // Request is the shared interface to jsonrpc2 messages that request
25 // a method be invoked.
26 // The request types are a closed set of *Call and *Notification.
27 type Request interface {
29 // Method is a string containing the method name to invoke.
31 // Params is either a struct or an array with the parameters of the method.
32 Params() json.RawMessage
33 // isJSONRPC2Request is used to make the set of request implementations closed.
37 // Notification is a request for which a response cannot occur, and as such
39 type Notification struct {
40 // Method is a string containing the method name to invoke.
42 params json.RawMessage
45 // Call is a request that expects a response.
46 // The response will have a matching ID.
48 // Method is a string containing the method name to invoke.
50 // Params is either a struct or an array with the parameters of the method.
51 params json.RawMessage
52 // id of this request, used to tie the Response back to the request.
56 // Response is a reply to a Call.
57 // It will have the same ID as the call it is a response to.
58 type Response struct {
59 // result is the content of the response.
60 result json.RawMessage
61 // err is set only if the call failed.
63 // ID of the request this is a response to.
67 // NewNotification constructs a new Notification message for the supplied
68 // method and parameters.
69 func NewNotification(method string, params interface{}) (*Notification, error) {
70 p, merr := marshalToRaw(params)
71 return &Notification{method: method, params: p}, merr
74 func (msg *Notification) Method() string { return msg.method }
75 func (msg *Notification) Params() json.RawMessage { return msg.params }
76 func (msg *Notification) isJSONRPC2Message() {}
77 func (msg *Notification) isJSONRPC2Request() {}
79 func (n *Notification) MarshalJSON() ([]byte, error) {
80 msg := wireRequest{Method: n.method, Params: &n.params}
81 data, err := json.Marshal(msg)
83 return data, fmt.Errorf("marshaling notification: %w", err)
88 func (n *Notification) UnmarshalJSON(data []byte) error {
90 if err := json.Unmarshal(data, &msg); err != nil {
91 return fmt.Errorf("unmarshaling notification: %w", err)
94 if msg.Params != nil {
95 n.params = *msg.Params
100 // NewCall constructs a new Call message for the supplied ID, method and
102 func NewCall(id ID, method string, params interface{}) (*Call, error) {
103 p, merr := marshalToRaw(params)
104 return &Call{id: id, method: method, params: p}, merr
107 func (msg *Call) Method() string { return msg.method }
108 func (msg *Call) Params() json.RawMessage { return msg.params }
109 func (msg *Call) ID() ID { return msg.id }
110 func (msg *Call) isJSONRPC2Message() {}
111 func (msg *Call) isJSONRPC2Request() {}
113 func (c *Call) MarshalJSON() ([]byte, error) {
114 msg := wireRequest{Method: c.method, Params: &c.params, ID: &c.id}
115 data, err := json.Marshal(msg)
117 return data, fmt.Errorf("marshaling call: %w", err)
122 func (c *Call) UnmarshalJSON(data []byte) error {
124 if err := json.Unmarshal(data, &msg); err != nil {
125 return fmt.Errorf("unmarshaling call: %w", err)
127 c.method = msg.Method
128 if msg.Params != nil {
129 c.params = *msg.Params
137 // NewResponse constructs a new Response message that is a reply to the
138 // supplied. If err is set result may be ignored.
139 func NewResponse(id ID, result interface{}, err error) (*Response, error) {
140 r, merr := marshalToRaw(result)
141 return &Response{id: id, result: r, err: err}, merr
144 func (msg *Response) ID() ID { return msg.id }
145 func (msg *Response) Result() json.RawMessage { return msg.result }
146 func (msg *Response) Err() error { return msg.err }
147 func (msg *Response) isJSONRPC2Message() {}
149 func (r *Response) MarshalJSON() ([]byte, error) {
150 msg := &wireResponse{Error: toWireError(r.err), ID: &r.id}
151 if msg.Error == nil {
152 msg.Result = &r.result
154 data, err := json.Marshal(msg)
156 return data, fmt.Errorf("marshaling notification: %w", err)
161 func toWireError(err error) *wireError {
163 // no error, the response is complete
166 if err, ok := err.(*wireError); ok {
167 // already a wire error, just use it
170 result := &wireError{Message: err.Error()}
171 var wrapped *wireError
172 if errors.As(err, &wrapped) {
173 // if we wrapped a wire error, keep the code from the wrapped error
174 // but the message from the outer error
175 result.Code = wrapped.Code
180 func (r *Response) UnmarshalJSON(data []byte) error {
181 msg := wireResponse{}
182 if err := json.Unmarshal(data, &msg); err != nil {
183 return fmt.Errorf("unmarshaling jsonrpc response: %w", err)
185 if msg.Result != nil {
186 r.result = *msg.Result
188 if msg.Error != nil {
197 func DecodeMessage(data []byte) (Message, error) {
198 msg := wireCombined{}
199 if err := json.Unmarshal(data, &msg); err != nil {
200 return nil, fmt.Errorf("unmarshaling jsonrpc message: %w", err)
202 if msg.Method == "" {
203 // no method, should be a response
205 return nil, ErrInvalidRequest
207 response := &Response{id: *msg.ID}
208 if msg.Error != nil {
209 response.err = msg.Error
211 if msg.Result != nil {
212 response.result = *msg.Result
216 // has a method, must be a request
218 // request with no ID is a notify
219 notify := &Notification{method: msg.Method}
220 if msg.Params != nil {
221 notify.params = *msg.Params
225 // request with an ID, must be a call
226 call := &Call{method: msg.Method, id: *msg.ID}
227 if msg.Params != nil {
228 call.params = *msg.Params
233 func marshalToRaw(obj interface{}) (json.RawMessage, error) {
234 data, err := json.Marshal(obj)
236 return json.RawMessage{}, err
238 return json.RawMessage(data), nil