golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/jsonrpc2/messages.go (about) 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 5 package jsonrpc2 6 7 import ( 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. 17 type 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. 26 type Request interface { 27 Message 28 // Method is a string containing the method name to invoke. 29 Method() string 30 // Params is an JSON value (object, array, null, or "") 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. 38 type 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. 46 type Call struct { 47 // Method is a string containing the method name to invoke. 48 method string 49 // Params is a JSON value (object, array, null, or "") 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. 57 type 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. 68 func NewNotification(method string, params interface{}) (*Notification, error) { 69 p, merr := marshalToRaw(params) 70 return &Notification{method: method, params: p}, merr 71 } 72 73 func (msg *Notification) Method() string { return msg.method } 74 func (msg *Notification) Params() json.RawMessage { return msg.params } 75 func (msg *Notification) isJSONRPC2Message() {} 76 func (msg *Notification) isJSONRPC2Request() {} 77 78 func (n *Notification) MarshalJSON() ([]byte, error) { 79 msg := wireRequest{Method: n.method, Params: &n.params} 80 data, err := json.Marshal(msg) 81 if err != nil { 82 return data, fmt.Errorf("marshaling notification: %w", err) 83 } 84 return data, nil 85 } 86 87 func (n *Notification) UnmarshalJSON(data []byte) error { 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. 101 func NewCall(id ID, method string, params interface{}) (*Call, error) { 102 p, merr := marshalToRaw(params) 103 return &Call{id: id, method: method, params: p}, merr 104 } 105 106 func (msg *Call) Method() string { return msg.method } 107 func (msg *Call) Params() json.RawMessage { return msg.params } 108 func (msg *Call) ID() ID { return msg.id } 109 func (msg *Call) isJSONRPC2Message() {} 110 func (msg *Call) isJSONRPC2Request() {} 111 112 func (c *Call) MarshalJSON() ([]byte, error) { 113 msg := wireRequest{Method: c.method, Params: &c.params, ID: &c.id} 114 data, err := json.Marshal(msg) 115 if err != nil { 116 return data, fmt.Errorf("marshaling call: %w", err) 117 } 118 return data, nil 119 } 120 121 func (c *Call) UnmarshalJSON(data []byte) error { 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. 138 func NewResponse(id ID, result interface{}, err error) (*Response, error) { 139 r, merr := marshalToRaw(result) 140 return &Response{id: id, result: r, err: err}, merr 141 } 142 143 func (msg *Response) ID() ID { return msg.id } 144 func (msg *Response) Result() json.RawMessage { return msg.result } 145 func (msg *Response) Err() error { return msg.err } 146 func (msg *Response) isJSONRPC2Message() {} 147 148 func (r *Response) MarshalJSON() ([]byte, error) { 149 msg := &wireResponse{Error: toWireError(r.err), ID: &r.id} 150 if msg.Error == nil { 151 msg.Result = &r.result 152 } 153 data, err := json.Marshal(msg) 154 if err != nil { 155 return data, fmt.Errorf("marshaling notification: %w", err) 156 } 157 return data, nil 158 } 159 160 func toWireError(err error) *WireError { 161 if err == nil { 162 // no error, the response is complete 163 return nil 164 } 165 if err, ok := err.(*WireError); ok { 166 // already a wire error, just use it 167 return err 168 } 169 result := &WireError{Message: err.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 179 func (r *Response) UnmarshalJSON(data []byte) error { 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 196 func DecodeMessage(data []byte) (Message, error) { 197 msg := wireCombined{} 198 if err := json.Unmarshal(data, &msg); err != nil { 199 return nil, fmt.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 nil, ErrInvalidRequest 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 response, nil 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{method: msg.Method} 219 if msg.Params != nil { 220 notify.params = *msg.Params 221 } 222 return notify, nil 223 } 224 // request with an ID, must be a call 225 call := &Call{method: msg.Method, id: *msg.ID} 226 if msg.Params != nil { 227 call.params = *msg.Params 228 } 229 return call, nil 230 } 231 232 func marshalToRaw(obj interface{}) (json.RawMessage, error) { 233 data, err := json.Marshal(obj) 234 if err != nil { 235 return json.RawMessage{}, err 236 } 237 return json.RawMessage(data), nil 238 }