github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/pkg/gethrpc/json.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package rpc
    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  
    36  	defaultWriteTimeout = 10 * time.Second // used if context has no deadline
    37  )
    38  
    39  var null = json.RawMessage("null")
    40  
    41  type subscriptionResult struct {
    42  	ID     string          `json:"subscription"`
    43  	Result json.RawMessage `json:"result,omitempty"`
    44  }
    45  
    46  // A value of this type can a JSON-RPC request, notification, successful response or
    47  // error response. Which one it is depends on the fields.
    48  type jsonrpcMessage struct {
    49  	Version string          `json:"jsonrpc,omitempty"`
    50  	ID      json.RawMessage `json:"id,omitempty"`
    51  	Method  string          `json:"method,omitempty"`
    52  	Params  json.RawMessage `json:"params,omitempty"`
    53  	Error   *jsonError      `json:"error,omitempty"`
    54  	Result  json.RawMessage `json:"result,omitempty"`
    55  }
    56  
    57  func (msg *jsonrpcMessage) isNotification() bool {
    58  	return msg.ID == nil && msg.Method != ""
    59  }
    60  
    61  func (msg *jsonrpcMessage) isCall() bool {
    62  	return msg.hasValidID() && msg.Method != ""
    63  }
    64  
    65  func (msg *jsonrpcMessage) isResponse() bool {
    66  	return msg.hasValidID() && msg.Method == "" && msg.Params == nil && (msg.Result != nil || msg.Error != nil)
    67  }
    68  
    69  func (msg *jsonrpcMessage) hasValidID() bool {
    70  	return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '['
    71  }
    72  
    73  func (msg *jsonrpcMessage) namespace() string {
    74  	elem := strings.SplitN(msg.Method, serviceMethodSeparator, 2)
    75  	return elem[0]
    76  }
    77  
    78  func (msg *jsonrpcMessage) String() string {
    79  	b, _ := json.Marshal(msg)
    80  	return string(b)
    81  }
    82  
    83  func (msg *jsonrpcMessage) errorResponse(err error) *jsonrpcMessage {
    84  	resp := errorMessage(err)
    85  	resp.ID = msg.ID
    86  	return resp
    87  }
    88  
    89  func (msg *jsonrpcMessage) response(result interface{}) *jsonrpcMessage {
    90  	enc, err := json.Marshal(result)
    91  	if err != nil {
    92  		// TODO: wrap with 'internal server error'
    93  		return msg.errorResponse(err)
    94  	}
    95  	return &jsonrpcMessage{Version: vsn, ID: msg.ID, Result: enc}
    96  }
    97  
    98  func errorMessage(err error) *jsonrpcMessage {
    99  	msg := &jsonrpcMessage{Version: vsn, ID: null, Error: &jsonError{
   100  		Code:    defaultErrorCode,
   101  		Message: err.Error(),
   102  	}}
   103  	ec, ok := err.(Error)
   104  	if ok {
   105  		msg.Error.Code = ec.ErrorCode()
   106  	}
   107  	return msg
   108  }
   109  
   110  type jsonError struct {
   111  	Code    int         `json:"code"`
   112  	Message string      `json:"message"`
   113  	Data    interface{} `json:"data,omitempty"`
   114  }
   115  
   116  func (err *jsonError) Error() string {
   117  	if err.Message == "" {
   118  		return fmt.Sprintf("json-rpc error %d", err.Code)
   119  	}
   120  	return err.Message
   121  }
   122  
   123  func (err *jsonError) ErrorCode() int {
   124  	return err.Code
   125  }
   126  
   127  // Conn is a subset of the methods of net.Conn which are sufficient for ServerCodec.
   128  type Conn interface {
   129  	io.ReadWriteCloser
   130  	SetWriteDeadline(time.Time) error
   131  }
   132  
   133  type deadlineCloser interface {
   134  	io.Closer
   135  	SetWriteDeadline(time.Time) error
   136  }
   137  
   138  // ConnRemoteAddr wraps the RemoteAddr operation, which returns a description
   139  // of the peer address of a connection. If a Conn also implements ConnRemoteAddr, this
   140  // description is used in log messages.
   141  type ConnRemoteAddr interface {
   142  	RemoteAddr() string
   143  }
   144  
   145  // connWithRemoteAddr overrides the remote address of a connection.
   146  type connWithRemoteAddr struct {
   147  	Conn
   148  	addr string
   149  }
   150  
   151  func (c connWithRemoteAddr) RemoteAddr() string { return c.addr }
   152  
   153  // jsonCodec reads and writes JSON-RPC messages to the underlying connection. It also has
   154  // support for parsing arguments and serializing (result) objects.
   155  type jsonCodec struct {
   156  	remoteAddr string
   157  	closer     sync.Once                 // close closed channel once
   158  	closed     chan interface{}          // closed on Close
   159  	decode     func(v interface{}) error // decoder to allow multiple transports
   160  	encMu      sync.Mutex                // guards the encoder
   161  	encode     func(v interface{}) error // encoder to allow multiple transports
   162  	conn       deadlineCloser
   163  }
   164  
   165  func newCodec(conn deadlineCloser, encode, decode func(v interface{}) error) ServerCodec {
   166  	codec := &jsonCodec{
   167  		closed: make(chan interface{}),
   168  		encode: encode,
   169  		decode: decode,
   170  		conn:   conn,
   171  	}
   172  	if ra, ok := conn.(ConnRemoteAddr); ok {
   173  		codec.remoteAddr = ra.RemoteAddr()
   174  	}
   175  	return codec
   176  }
   177  
   178  // NewJSONCodec creates a codec that reads from the given connection. If conn implements
   179  // ConnRemoteAddr, log messages will use it to include the remote address of the
   180  // connection.
   181  func NewJSONCodec(conn Conn) ServerCodec {
   182  	enc := json.NewEncoder(conn)
   183  	dec := json.NewDecoder(conn)
   184  	dec.UseNumber()
   185  	return newCodec(conn, enc.Encode, dec.Decode)
   186  }
   187  
   188  func (c *jsonCodec) RemoteAddr() string {
   189  	return c.remoteAddr
   190  }
   191  
   192  func (c *jsonCodec) Read() (msg []*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  	msg, batch = parseMessage(rawmsg)
   200  	return msg, batch, nil
   201  }
   202  
   203  // Write sends a message to client.
   204  func (c *jsonCodec) Write(ctx context.Context, v interface{}) error {
   205  	c.encMu.Lock()
   206  	defer c.encMu.Unlock()
   207  
   208  	deadline, ok := ctx.Deadline()
   209  	if !ok {
   210  		deadline = time.Now().Add(defaultWriteTimeout)
   211  	}
   212  	c.conn.SetWriteDeadline(deadline)
   213  	return c.encode(v)
   214  }
   215  
   216  // Close the underlying connection
   217  func (c *jsonCodec) Close() {
   218  	c.closer.Do(func() {
   219  		close(c.closed)
   220  		c.conn.Close()
   221  	})
   222  }
   223  
   224  // Closed returns a channel which will be closed when Close is called
   225  func (c *jsonCodec) Closed() <-chan interface{} {
   226  	return c.closed
   227  }
   228  
   229  // parseMessage parses raw bytes as a (batch of) JSON-RPC message(s). There are no error
   230  // checks in this function because the raw message has already been syntax-checked when it
   231  // is called. Any non-JSON-RPC messages in the input return the zero value of
   232  // jsonrpcMessage.
   233  func parseMessage(raw json.RawMessage) ([]*jsonrpcMessage, bool) {
   234  	if !isBatch(raw) {
   235  		msgs := []*jsonrpcMessage{{}}
   236  		json.Unmarshal(raw, &msgs[0])
   237  		return msgs, false
   238  	}
   239  	dec := json.NewDecoder(bytes.NewReader(raw))
   240  	dec.Token() // skip '['
   241  	var msgs []*jsonrpcMessage
   242  	for dec.More() {
   243  		msgs = append(msgs, new(jsonrpcMessage))
   244  		dec.Decode(&msgs[len(msgs)-1])
   245  	}
   246  	return msgs, true
   247  }
   248  
   249  // isBatch returns true when the first non-whitespace characters is '['
   250  func isBatch(raw json.RawMessage) bool {
   251  	for _, c := range raw {
   252  		// skip insignificant whitespace (http://www.ietf.org/rfc/rfc4627.txt)
   253  		if c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d {
   254  			continue
   255  		}
   256  		return c == '['
   257  	}
   258  	return false
   259  }
   260  
   261  // parsePositionalArguments tries to parse the given args to an array of values with the
   262  // given types. It returns the parsed values or an error when the args could not be
   263  // parsed. Missing optional arguments are returned as reflect.Zero values.
   264  func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) {
   265  	dec := json.NewDecoder(bytes.NewReader(rawArgs))
   266  	var args []reflect.Value
   267  	tok, err := dec.Token()
   268  	switch {
   269  	case err == io.EOF || tok == nil && err == nil:
   270  		// "params" is optional and may be empty. Also allow "params":null even though it's
   271  		// not in the spec because our own client used to send it.
   272  	case err != nil:
   273  		return nil, err
   274  	case tok == json.Delim('['):
   275  		// Read argument array.
   276  		if args, err = parseArgumentArray(dec, types); err != nil {
   277  			return nil, err
   278  		}
   279  	default:
   280  		return nil, errors.New("non-array args")
   281  	}
   282  	// Set any missing args to nil.
   283  	for i := len(args); i < len(types); i++ {
   284  		if types[i].Kind() != reflect.Ptr {
   285  			return nil, fmt.Errorf("missing value for required argument %d", i)
   286  		}
   287  		args = append(args, reflect.Zero(types[i]))
   288  	}
   289  	return args, nil
   290  }
   291  
   292  func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Value, error) {
   293  	args := make([]reflect.Value, 0, len(types))
   294  	for i := 0; dec.More(); i++ {
   295  		if i >= len(types) {
   296  			return args, fmt.Errorf("too many arguments, want at most %d", len(types))
   297  		}
   298  		argval := reflect.New(types[i])
   299  		if err := dec.Decode(argval.Interface()); err != nil {
   300  			return args, fmt.Errorf("invalid argument %d: %v", i, err)
   301  		}
   302  		if argval.IsNil() && types[i].Kind() != reflect.Ptr {
   303  			return args, fmt.Errorf("missing value for required argument %d", i)
   304  		}
   305  		args = append(args, argval.Elem())
   306  	}
   307  	// Read end of args array.
   308  	_, err := dec.Token()
   309  	return args, err
   310  }
   311  
   312  // parseSubscriptionName extracts the subscription name from an encoded argument array.
   313  func parseSubscriptionName(rawArgs json.RawMessage) (string, error) {
   314  	dec := json.NewDecoder(bytes.NewReader(rawArgs))
   315  	if tok, _ := dec.Token(); tok != json.Delim('[') {
   316  		return "", errors.New("non-array args")
   317  	}
   318  	v, _ := dec.Token()
   319  	method, ok := v.(string)
   320  	if !ok {
   321  		return "", errors.New("expected subscription name as first argument")
   322  	}
   323  	return method, nil
   324  }