GoPLS Viewer

Home|gopls/internal/jsonrpc2/messages.go
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.
4
5package jsonrpc2
6
7import (
8    "encoding/json"
9    "errors"
10    "fmt"
11)
12
13// Message is the interface to all jsonrpc2 message types.
14// They share no common functionality, but are a closed set of concrete types
15// that are allowed to implement this interface. The message types are *Call,
16// *Notification and *Response.
17type Message interface {
18    // isJSONRPC2Message is used to make the set of message implementations a
19    // closed set.
20    isJSONRPC2Message()
21}
22
23// Request is the shared interface to jsonrpc2 messages that request
24// a method be invoked.
25// The request types are a closed set of *Call and *Notification.
26type Request interface {
27    Message
28    // Method is a string containing the method name to invoke.
29    Method() string
30    // Params is either a struct or an array with the parameters of the method.
31    Params() json.RawMessage
32    // isJSONRPC2Request is used to make the set of request implementations closed.
33    isJSONRPC2Request()
34}
35
36// Notification is a request for which a response cannot occur, and as such
37// it has not ID.
38type Notification struct {
39    // Method is a string containing the method name to invoke.
40    method string
41    params json.RawMessage
42}
43
44// Call is a request that expects a response.
45// The response will have a matching ID.
46type Call struct {
47    // Method is a string containing the method name to invoke.
48    method string
49    // Params is either a struct or an array with the parameters of the method.
50    params json.RawMessage
51    // id of this request, used to tie the Response back to the request.
52    id ID
53}
54
55// Response is a reply to a Call.
56// It will have the same ID as the call it is a response to.
57type Response struct {
58    // result is the content of the response.
59    result json.RawMessage
60    // err is set only if the call failed.
61    err error
62    // ID of the request this is a response to.
63    id ID
64}
65
66// NewNotification constructs a new Notification message for the supplied
67// method and parameters.
68func NewNotification(method stringparams interface{}) (*Notificationerror) {
69    pmerr := marshalToRaw(params)
70    return &Notification{methodmethodparamsp}, merr
71}
72
73func (msg *NotificationMethod() string          { return msg.method }
74func (msg *NotificationParams() json.RawMessage { return msg.params }
75func (msg *NotificationisJSONRPC2Message()      {}
76func (msg *NotificationisJSONRPC2Request()      {}
77
78func (n *NotificationMarshalJSON() ([]byteerror) {
79    msg := wireRequest{Methodn.methodParams: &n.params}
80    dataerr := json.Marshal(msg)
81    if err != nil {
82        return datafmt.Errorf("marshaling notification: %w"err)
83    }
84    return datanil
85}
86
87func (n *NotificationUnmarshalJSON(data []byteerror {
88    msg := wireRequest{}
89    if err := json.Unmarshal(data, &msg); err != nil {
90        return fmt.Errorf("unmarshaling notification: %w"err)
91    }
92    n.method = msg.Method
93    if msg.Params != nil {
94        n.params = *msg.Params
95    }
96    return nil
97}
98
99// NewCall constructs a new Call message for the supplied ID, method and
100// parameters.
101func NewCall(id IDmethod stringparams interface{}) (*Callerror) {
102    pmerr := marshalToRaw(params)
103    return &Call{ididmethodmethodparamsp}, merr
104}
105
106func (msg *CallMethod() string          { return msg.method }
107func (msg *CallParams() json.RawMessage { return msg.params }
108func (msg *CallID() ID                  { return msg.id }
109func (msg *CallisJSONRPC2Message()      {}
110func (msg *CallisJSONRPC2Request()      {}
111
112func (c *CallMarshalJSON() ([]byteerror) {
113    msg := wireRequest{Methodc.methodParams: &c.paramsID: &c.id}
114    dataerr := json.Marshal(msg)
115    if err != nil {
116        return datafmt.Errorf("marshaling call: %w"err)
117    }
118    return datanil
119}
120
121func (c *CallUnmarshalJSON(data []byteerror {
122    msg := wireRequest{}
123    if err := json.Unmarshal(data, &msg); err != nil {
124        return fmt.Errorf("unmarshaling call: %w"err)
125    }
126    c.method = msg.Method
127    if msg.Params != nil {
128        c.params = *msg.Params
129    }
130    if msg.ID != nil {
131        c.id = *msg.ID
132    }
133    return nil
134}
135
136// NewResponse constructs a new Response message that is a reply to the
137// supplied. If err is set result may be ignored.
138func NewResponse(id IDresult interface{}, err error) (*Responseerror) {
139    rmerr := marshalToRaw(result)
140    return &Response{ididresultrerrerr}, merr
141}
142
143func (msg *ResponseID() ID                  { return msg.id }
144func (msg *ResponseResult() json.RawMessage { return msg.result }
145func (msg *ResponseErr() error              { return msg.err }
146func (msg *ResponseisJSONRPC2Message()      {}
147
148func (r *ResponseMarshalJSON() ([]byteerror) {
149    msg := &wireResponse{ErrortoWireError(r.err), ID: &r.id}
150    if msg.Error == nil {
151        msg.Result = &r.result
152    }
153    dataerr := json.Marshal(msg)
154    if err != nil {
155        return datafmt.Errorf("marshaling notification: %w"err)
156    }
157    return datanil
158}
159
160func toWireError(err error) *wireError {
161    if err == nil {
162        // no error, the response is complete
163        return nil
164    }
165    if errok := err.(*wireError); ok {
166        // already a wire error, just use it
167        return err
168    }
169    result := &wireError{Messageerr.Error()}
170    var wrapped *wireError
171    if errors.As(err, &wrapped) {
172        // if we wrapped a wire error, keep the code from the wrapped error
173        // but the message from the outer error
174        result.Code = wrapped.Code
175    }
176    return result
177}
178
179func (r *ResponseUnmarshalJSON(data []byteerror {
180    msg := wireResponse{}
181    if err := json.Unmarshal(data, &msg); err != nil {
182        return fmt.Errorf("unmarshaling jsonrpc response: %w"err)
183    }
184    if msg.Result != nil {
185        r.result = *msg.Result
186    }
187    if msg.Error != nil {
188        r.err = msg.Error
189    }
190    if msg.ID != nil {
191        r.id = *msg.ID
192    }
193    return nil
194}
195
196func DecodeMessage(data []byte) (Messageerror) {
197    msg := wireCombined{}
198    if err := json.Unmarshal(data, &msg); err != nil {
199        return nilfmt.Errorf("unmarshaling jsonrpc message: %w"err)
200    }
201    if msg.Method == "" {
202        // no method, should be a response
203        if msg.ID == nil {
204            return nilErrInvalidRequest
205        }
206        response := &Response{id: *msg.ID}
207        if msg.Error != nil {
208            response.err = msg.Error
209        }
210        if msg.Result != nil {
211            response.result = *msg.Result
212        }
213        return responsenil
214    }
215    // has a method, must be a request
216    if msg.ID == nil {
217        // request with no ID is a notify
218        notify := &Notification{methodmsg.Method}
219        if msg.Params != nil {
220            notify.params = *msg.Params
221        }
222        return notifynil
223    }
224    // request with an ID, must be a call
225    call := &Call{methodmsg.Methodid: *msg.ID}
226    if msg.Params != nil {
227        call.params = *msg.Params
228    }
229    return callnil
230}
231
232func marshalToRaw(obj interface{}) (json.RawMessageerror) {
233    dataerr := json.Marshal(obj)
234    if err != nil {
235        return json.RawMessage{}, err
236    }
237    return json.RawMessage(data), nil
238}
239
MembersX
Call.UnmarshalJSON.msg
Notification
NewNotification.params
Call.isJSONRPC2Message
Call.MarshalJSON.msg
toWireError.wrapped
marshalToRaw.data
Notification.UnmarshalJSON.data
Notification.UnmarshalJSON.msg
NewCall.params
Response.Err
Call.isJSONRPC2Message.msg
DecodeMessage.call
Call
Call.params
Notification.isJSONRPC2Message
Call.ID.msg
NewResponse.id
toWireError
DecodeMessage
NewNotification
Notification.Params
Call.Method
Call.isJSONRPC2Request.msg
Notification.MarshalJSON
Call.Method.msg
Call.ID
Response.Result.msg
Notification.method
Call.id
Response
Notification.isJSONRPC2Request.msg
Response.Err.msg
Response.MarshalJSON.msg
errors
Call.isJSONRPC2Request
Response.UnmarshalJSON.r
Response.UnmarshalJSON.msg
Response.err
NewNotification.method
Notification.UnmarshalJSON
Response.UnmarshalJSON
NewCall.p
Call.UnmarshalJSON.data
Response.UnmarshalJSON.data
Response.UnmarshalJSON.err
Notification.params
NewNotification.merr
Notification.UnmarshalJSON.err
NewCall.id
DecodeMessage.data
marshalToRaw.obj
NewResponse
NewNotification.p
Notification.MarshalJSON.data
NewCall
Call.UnmarshalJSON.c
NewResponse.result
NewResponse.err
Response.ID
Response.isJSONRPC2Message.msg
Request
Response.result
Call.Params.msg
Call.MarshalJSON
toWireError.err
DecodeMessage.BlockStmt.notify
marshalToRaw
Response.MarshalJSON.r
DecodeMessage.msg
Notification.Method
Notification.MarshalJSON.msg
Call.MarshalJSON.data
Response.isJSONRPC2Message
Call.MarshalJSON.err
NewResponse.merr
Call.UnmarshalJSON.err
Response.ID.msg
Response.Result
DecodeMessage.BlockStmt.response
Message
Call.method
Notification.Params.msg
NewCall.merr
toWireError.result
DecodeMessage.err
Notification.Method.msg
Notification.isJSONRPC2Message.msg
Call.UnmarshalJSON
Response.MarshalJSON
NewCall.method
Call.MarshalJSON.c
NewResponse.r
Response.MarshalJSON.data
Response.id
Notification.MarshalJSON.n
Notification.MarshalJSON.err
Notification.UnmarshalJSON.n
marshalToRaw.err
Notification.isJSONRPC2Request
Call.Params
Response.MarshalJSON.err
Members
X