github.com/amazechain/amc@v0.1.3/modules/rpc/jsonrpc/json.go (about) 1 // Copyright 2022 The AmazeChain Authors 2 // This file is part of the AmazeChain library. 3 // 4 // The AmazeChain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The AmazeChain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package jsonrpc 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io" 26 "reflect" 27 "strings" 28 "sync" 29 "time" 30 ) 31 32 const ( 33 vsn = "2.0" 34 serviceMethodSeparator = "_" 35 subscribeMethodSuffix = "_subscribe" 36 notificationMethodSuffix = "_subscription" 37 unsubscribeMethodSuffix = "_unsubscribe" 38 39 defaultWriteTimeout = 10 * time.Second 40 ) 41 42 var null = json.RawMessage("null") 43 44 type subscriptionResult struct { 45 ID string `json:"subscription"` 46 Result json.RawMessage `json:"result,omitempty"` 47 } 48 49 type jsonrpcMessage struct { 50 Version string `json:"jsonrpc,omitempty"` 51 ID json.RawMessage `json:"id,omitempty"` 52 Method string `json:"method,omitempty"` 53 Params json.RawMessage `json:"params,omitempty"` 54 Error *jsonError `json:"error,omitempty"` 55 Result json.RawMessage `json:"result,omitempty"` 56 } 57 58 func (msg *jsonrpcMessage) isNotification() bool { 59 return msg.ID == nil && msg.Method != "" 60 } 61 62 func (msg *jsonrpcMessage) isCall() bool { 63 return msg.hasValidID() && msg.Method != "" 64 } 65 66 func (msg *jsonrpcMessage) isResponse() bool { 67 return msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil) 68 } 69 70 func (msg *jsonrpcMessage) hasValidID() bool { 71 return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '[' 72 } 73 74 func (msg *jsonrpcMessage) isSubscribe() bool { 75 return strings.HasSuffix(msg.Method, subscribeMethodSuffix) 76 } 77 78 func (msg *jsonrpcMessage) isUnsubscribe() bool { 79 return strings.HasSuffix(msg.Method, unsubscribeMethodSuffix) 80 } 81 82 func (msg *jsonrpcMessage) namespace() string { 83 elem := strings.SplitN(msg.Method, serviceMethodSeparator, 2) 84 return elem[0] 85 } 86 87 func (msg *jsonrpcMessage) String() string { 88 b, _ := json.Marshal(msg) 89 return string(b) 90 } 91 92 func (msg *jsonrpcMessage) errorResponse(err error) *jsonrpcMessage { 93 resp := errorMessage(err) 94 resp.ID = msg.ID 95 return resp 96 } 97 98 func (msg *jsonrpcMessage) response(result interface{}) *jsonrpcMessage { 99 enc, err := json.Marshal(result) 100 if err != nil { 101 // TODO: wrap with 'internal server error' 102 return msg.errorResponse(err) 103 } 104 return &jsonrpcMessage{Version: vsn, ID: msg.ID, Result: enc} 105 } 106 107 func errorMessage(err error) *jsonrpcMessage { 108 msg := &jsonrpcMessage{Version: vsn, ID: null, Error: &jsonError{ 109 Code: defaultErrorCode, 110 Message: err.Error(), 111 }} 112 ec, ok := err.(Error) 113 if ok { 114 msg.Error.Code = ec.ErrorCode() 115 } 116 de, ok := err.(DataError) 117 if ok { 118 msg.Error.Data = de.ErrorData() 119 } 120 return msg 121 } 122 123 type jsonError struct { 124 Code int `json:"code"` 125 Message string `json:"message"` 126 Data interface{} `json:"data,omitempty"` 127 } 128 129 func (err *jsonError) Error() string { 130 if err.Message == "" { 131 return fmt.Sprintf("json-rpc error %d", err.Code) 132 } 133 return err.Message 134 } 135 136 func (err *jsonError) ErrorCode() int { 137 return err.Code 138 } 139 140 func (err *jsonError) ErrorData() interface{} { 141 return err.Data 142 } 143 144 type Conn interface { 145 io.ReadWriteCloser 146 SetWriteDeadline(time.Time) error 147 } 148 149 type deadlineCloser interface { 150 io.Closer 151 SetWriteDeadline(time.Time) error 152 } 153 154 type ConnRemoteAddr interface { 155 RemoteAddr() string 156 } 157 158 type jsonCodec struct { 159 remote string 160 closer sync.Once 161 closeCh chan interface{} 162 decode func(v interface{}) error 163 encMu sync.Mutex 164 encode func(v interface{}) error 165 conn deadlineCloser 166 } 167 168 func NewFuncCodec(conn deadlineCloser, encode, decode func(v interface{}) error) ServerCodec { 169 codec := &jsonCodec{ 170 closeCh: make(chan interface{}), 171 encode: encode, 172 decode: decode, 173 conn: conn, 174 } 175 if ra, ok := conn.(ConnRemoteAddr); ok { 176 codec.remote = ra.RemoteAddr() 177 } 178 return codec 179 } 180 181 func NewCodec(conn Conn) ServerCodec { 182 enc := json.NewEncoder(conn) 183 dec := json.NewDecoder(conn) 184 dec.UseNumber() 185 return NewFuncCodec(conn, enc.Encode, dec.Decode) 186 } 187 188 func (c *jsonCodec) remoteAddr() string { 189 return c.remote 190 } 191 192 func (c *jsonCodec) readBatch() (messages []*jsonrpcMessage, batch bool, err error) { 193 // Decode the next JSON object in the input stream. 194 // This verifies basic syntax, etc. 195 var rawmsg json.RawMessage 196 if err := c.decode(&rawmsg); err != nil { 197 return nil, false, err 198 } 199 messages, batch = parseMessage(rawmsg) 200 for i, msg := range messages { 201 if msg == nil { 202 // Message is JSON 'null'. Replace with zero value so it 203 // will be treated like any other invalid message. 204 messages[i] = new(jsonrpcMessage) 205 } 206 } 207 return messages, batch, nil 208 } 209 210 func (c *jsonCodec) writeJSON(ctx context.Context, v interface{}) error { 211 c.encMu.Lock() 212 defer c.encMu.Unlock() 213 214 deadline, ok := ctx.Deadline() 215 if !ok { 216 deadline = time.Now().Add(defaultWriteTimeout) 217 } 218 c.conn.SetWriteDeadline(deadline) 219 return c.encode(v) 220 } 221 222 func (c *jsonCodec) close() { 223 c.closer.Do(func() { 224 close(c.closeCh) 225 c.conn.Close() 226 }) 227 } 228 229 // Closed returns a channel which will be closed when Close is called 230 func (c *jsonCodec) closed() <-chan interface{} { 231 return c.closeCh 232 } 233 234 func parseMessage(raw json.RawMessage) ([]*jsonrpcMessage, bool) { 235 if !isBatch(raw) { 236 msgs := []*jsonrpcMessage{{}} 237 json.Unmarshal(raw, &msgs[0]) 238 return msgs, false 239 } 240 dec := json.NewDecoder(bytes.NewReader(raw)) 241 dec.Token() // skip '[' 242 var msgs []*jsonrpcMessage 243 for dec.More() { 244 msgs = append(msgs, new(jsonrpcMessage)) 245 dec.Decode(&msgs[len(msgs)-1]) 246 } 247 return msgs, true 248 } 249 250 // isBatch returns true when the first non-whitespace characters is '[' 251 func isBatch(raw json.RawMessage) bool { 252 for _, c := range raw { 253 // skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt) 254 if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d { 255 continue 256 } 257 return c == '[' 258 } 259 return false 260 } 261 262 func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) { 263 dec := json.NewDecoder(bytes.NewReader(rawArgs)) 264 var args []reflect.Value 265 tok, err := dec.Token() 266 switch { 267 case err == io.EOF || tok == nil && err == nil: 268 case err != nil: 269 return nil, err 270 case tok == json.Delim('['): 271 if args, err = parseArgumentArray(dec, types); err != nil { 272 return nil, err 273 } 274 default: 275 return nil, errors.New("non-array args") 276 } 277 for i := len(args); i < len(types); i++ { 278 if types[i].Kind() != reflect.Ptr { 279 return nil, fmt.Errorf("missing value for required argument %d", i) 280 } 281 args = append(args, reflect.Zero(types[i])) 282 } 283 return args, nil 284 } 285 286 func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Value, error) { 287 args := make([]reflect.Value, 0, len(types)) 288 for i := 0; dec.More(); i++ { 289 if i >= len(types) { 290 return args, fmt.Errorf("too many arguments, want at most %d", len(types)) 291 } 292 argval := reflect.New(types[i]) 293 if err := dec.Decode(argval.Interface()); err != nil { 294 return args, fmt.Errorf("invalid argument %d: %v", i, err) 295 } 296 if argval.IsNil() && types[i].Kind() != reflect.Ptr { 297 return args, fmt.Errorf("missing value for required argument %d", i) 298 } 299 args = append(args, argval.Elem()) 300 } 301 _, err := dec.Token() 302 return args, err 303 } 304 305 func parseSubscriptionName(rawArgs json.RawMessage) (string, error) { 306 dec := json.NewDecoder(bytes.NewReader(rawArgs)) 307 if tok, _ := dec.Token(); tok != json.Delim('[') { 308 return "", errors.New("non-array args") 309 } 310 v, _ := dec.Token() 311 method, ok := v.(string) 312 if !ok { 313 return "", errors.New("expected subscription name as first argument") 314 } 315 return method, nil 316 }