github.com/v2fly/tools@v0.100.0/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 "fmt" 10 11 errors "golang.org/x/xerrors" 12 ) 13 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 20 // closed set. 21 isJSONRPC2Message() 22 } 23 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 { 28 Message 29 // Method is a string containing the method name to invoke. 30 Method() string 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. 34 isJSONRPC2Request() 35 } 36 37 // Notification is a request for which a response cannot occur, and as such 38 // it has not ID. 39 type Notification struct { 40 // Method is a string containing the method name to invoke. 41 method string 42 params json.RawMessage 43 } 44 45 // Call is a request that expects a response. 46 // The response will have a matching ID. 47 type Call struct { 48 // Method is a string containing the method name to invoke. 49 method string 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. 53 id ID 54 } 55 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. 62 err error 63 // ID of the request this is a response to. 64 id ID 65 } 66 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 72 } 73 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() {} 78 79 func (n *Notification) MarshalJSON() ([]byte, error) { 80 msg := wireRequest{Method: n.method, Params: &n.params} 81 data, err := json.Marshal(msg) 82 if err != nil { 83 return data, fmt.Errorf("marshaling notification: %w", err) 84 } 85 return data, nil 86 } 87 88 func (n *Notification) UnmarshalJSON(data []byte) error { 89 msg := wireRequest{} 90 if err := json.Unmarshal(data, &msg); err != nil { 91 return fmt.Errorf("unmarshaling notification: %w", err) 92 } 93 n.method = msg.Method 94 if msg.Params != nil { 95 n.params = *msg.Params 96 } 97 return nil 98 } 99 100 // NewCall constructs a new Call message for the supplied ID, method and 101 // parameters. 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 105 } 106 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() {} 112 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) 116 if err != nil { 117 return data, fmt.Errorf("marshaling call: %w", err) 118 } 119 return data, nil 120 } 121 122 func (c *Call) UnmarshalJSON(data []byte) error { 123 msg := wireRequest{} 124 if err := json.Unmarshal(data, &msg); err != nil { 125 return fmt.Errorf("unmarshaling call: %w", err) 126 } 127 c.method = msg.Method 128 if msg.Params != nil { 129 c.params = *msg.Params 130 } 131 if msg.ID != nil { 132 c.id = *msg.ID 133 } 134 return nil 135 } 136 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 142 } 143 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() {} 148 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 153 } 154 data, err := json.Marshal(msg) 155 if err != nil { 156 return data, fmt.Errorf("marshaling notification: %w", err) 157 } 158 return data, nil 159 } 160 161 func toWireError(err error) *wireError { 162 if err == nil { 163 // no error, the response is complete 164 return nil 165 } 166 if err, ok := err.(*wireError); ok { 167 // already a wire error, just use it 168 return err 169 } 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 176 } 177 return result 178 } 179 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) 184 } 185 if msg.Result != nil { 186 r.result = *msg.Result 187 } 188 if msg.Error != nil { 189 r.err = msg.Error 190 } 191 if msg.ID != nil { 192 r.id = *msg.ID 193 } 194 return nil 195 } 196 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) 201 } 202 if msg.Method == "" { 203 // no method, should be a response 204 if msg.ID == nil { 205 return nil, ErrInvalidRequest 206 } 207 response := &Response{id: *msg.ID} 208 if msg.Error != nil { 209 response.err = msg.Error 210 } 211 if msg.Result != nil { 212 response.result = *msg.Result 213 } 214 return response, nil 215 } 216 // has a method, must be a request 217 if msg.ID == nil { 218 // request with no ID is a notify 219 notify := &Notification{method: msg.Method} 220 if msg.Params != nil { 221 notify.params = *msg.Params 222 } 223 return notify, nil 224 } 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 229 } 230 return call, nil 231 } 232 233 func marshalToRaw(obj interface{}) (json.RawMessage, error) { 234 data, err := json.Marshal(obj) 235 if err != nil { 236 return json.RawMessage{}, err 237 } 238 return json.RawMessage(data), nil 239 }