GoPLS Viewer

Home|gopls/internal/jsonrpc2_v2/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// ID is a Request identifier.
14type ID struct {
15    value interface{}
16}
17
18// Message is the interface to all jsonrpc2 message types.
19// They share no common functionality, but are a closed set of concrete types
20// that are allowed to implement this interface. The message types are *Request
21// and *Response.
22type Message interface {
23    // marshal builds the wire form from the API form.
24    // It is private, which makes the set of Message implementations closed.
25    marshal(to *wireCombined)
26}
27
28// Request is a Message sent to a peer to request behavior.
29// If it has an ID it is a call, otherwise it is a notification.
30type Request struct {
31    // ID of this request, used to tie the Response back to the request.
32    // This will be nil for notifications.
33    ID ID
34    // Method is a string containing the method name to invoke.
35    Method string
36    // Params is either a struct or an array with the parameters of the method.
37    Params json.RawMessage
38}
39
40// Response is a Message used as a reply to a call Request.
41// It will have the same ID as the call it is a response to.
42type Response struct {
43    // result is the content of the response.
44    Result json.RawMessage
45    // err is set only if the call failed.
46    Error error
47    // id of the request this is a response to.
48    ID ID
49}
50
51// StringID creates a new string request identifier.
52func StringID(s stringID { return ID{values} }
53
54// Int64ID creates a new integer request identifier.
55func Int64ID(i int64ID { return ID{valuei} }
56
57// IsValid returns true if the ID is a valid identifier.
58// The default value for ID will return false.
59func (id IDIsValid() bool { return id.value != nil }
60
61// Raw returns the underlying value of the ID.
62func (id IDRaw() interface{} { return id.value }
63
64// NewNotification constructs a new Notification message for the supplied
65// method and parameters.
66func NewNotification(method stringparams interface{}) (*Requesterror) {
67    pmerr := marshalToRaw(params)
68    return &Request{MethodmethodParamsp}, merr
69}
70
71// NewCall constructs a new Call message for the supplied ID, method and
72// parameters.
73func NewCall(id IDmethod stringparams interface{}) (*Requesterror) {
74    pmerr := marshalToRaw(params)
75    return &Request{IDidMethodmethodParamsp}, merr
76}
77
78func (msg *RequestIsCall() bool { return msg.ID.IsValid() }
79
80func (msg *Requestmarshal(to *wireCombined) {
81    to.ID = msg.ID.value
82    to.Method = msg.Method
83    to.Params = msg.Params
84}
85
86// NewResponse constructs a new Response message that is a reply to the
87// supplied. If err is set result may be ignored.
88func NewResponse(id IDresult interface{}, rerr error) (*Responseerror) {
89    rmerr := marshalToRaw(result)
90    return &Response{IDidResultrErrorrerr}, merr
91}
92
93func (msg *Responsemarshal(to *wireCombined) {
94    to.ID = msg.ID.value
95    to.Error = toWireError(msg.Error)
96    to.Result = msg.Result
97}
98
99func toWireError(err error) *wireError {
100    if err == nil {
101        // no error, the response is complete
102        return nil
103    }
104    if errok := err.(*wireError); ok {
105        // already a wire error, just use it
106        return err
107    }
108    result := &wireError{Messageerr.Error()}
109    var wrapped *wireError
110    if errors.As(err, &wrapped) {
111        // if we wrapped a wire error, keep the code from the wrapped error
112        // but the message from the outer error
113        result.Code = wrapped.Code
114    }
115    return result
116}
117
118func EncodeMessage(msg Message) ([]byteerror) {
119    wire := wireCombined{VersionTagwireVersion}
120    msg.marshal(&wire)
121    dataerr := json.Marshal(&wire)
122    if err != nil {
123        return datafmt.Errorf("marshaling jsonrpc message: %w"err)
124    }
125    return datanil
126}
127
128func DecodeMessage(data []byte) (Messageerror) {
129    msg := wireCombined{}
130    if err := json.Unmarshal(data, &msg); err != nil {
131        return nilfmt.Errorf("unmarshaling jsonrpc message: %w"err)
132    }
133    if msg.VersionTag != wireVersion {
134        return nilfmt.Errorf("invalid message version tag %s expected %s"msg.VersionTagwireVersion)
135    }
136    id := ID{}
137    switch v := msg.ID.(type) {
138    case nil:
139    case float64:
140        // coerce the id type to int64 if it is float64, the spec does not allow fractional parts
141        id = Int64ID(int64(v))
142    case int64:
143        id = Int64ID(v)
144    case string:
145        id = StringID(v)
146    default:
147        return nilfmt.Errorf("invalid message id type <%T>%v"vv)
148    }
149    if msg.Method != "" {
150        // has a method, must be a call
151        return &Request{
152            Methodmsg.Method,
153            ID:     id,
154            Paramsmsg.Params,
155        }, nil
156    }
157    // no method, should be a response
158    if !id.IsValid() {
159        return nilErrInvalidRequest
160    }
161    resp := &Response{
162        ID:     id,
163        Resultmsg.Result,
164    }
165    // we have to check if msg.Error is nil to avoid a typed error
166    if msg.Error != nil {
167        resp.Error = msg.Error
168    }
169    return respnil
170}
171
172func marshalToRaw(obj interface{}) (json.RawMessageerror) {
173    if obj == nil {
174        return nilnil
175    }
176    dataerr := json.Marshal(obj)
177    if err != nil {
178        return nilerr
179    }
180    return json.RawMessage(data), nil
181}
182
MembersX
NewResponse.merr
NewCall.method
Response.ID
NewNotification.p
EncodeMessage.wire
toWireError.result
Int64ID.i
NewCall
DecodeMessage
Request.Params
NewNotification.method
Response.marshal.msg
ID.Raw
NewCall.p
Request.IsCall.msg
NewResponse
NewResponse.id
ID
Request
StringID.s
toWireError.wrapped
NewResponse.rerr
Response.marshal.to
DecodeMessage.data
StringID
NewNotification.merr
Request.IsCall
NewResponse.r
Response.marshal
DecodeMessage.id
NewCall.params
EncodeMessage.data
marshalToRaw.data
Request.marshal.to
DecodeMessage.err
Response
NewNotification
NewNotification.params
toWireError
EncodeMessage
ID.IsValid.id
NewCall.id
Request.marshal
marshalToRaw.err
Int64ID
ID.Raw.id
toWireError.err
DecodeMessage.resp
marshalToRaw.obj
Request.ID
ID.IsValid
Request.marshal.msg
NewResponse.result
EncodeMessage.err
marshalToRaw
ID.value
Request.Method
Response.Result
EncodeMessage.msg
DecodeMessage.msg
Message
Response.Error
NewCall.merr
Members
X