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  }