github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/services/rpcsrv/params/types.go (about)

     1  package params
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  
    10  	"github.com/nspcc-dev/neo-go/pkg/neorpc"
    11  )
    12  
    13  const (
    14  	// maxBatchSize is the maximum number of requests per batch.
    15  	maxBatchSize = 100
    16  )
    17  
    18  // Request contains standard JSON-RPC 2.0 request and batch of
    19  // requests: http://www.jsonrpc.org/specification.
    20  // It's used in server to represent incoming queries.
    21  type Request struct {
    22  	In    *In
    23  	Batch Batch
    24  }
    25  
    26  // In represents a standard JSON-RPC 2.0
    27  // request: http://www.jsonrpc.org/specification#request_object.
    28  type In struct {
    29  	JSONRPC   string          `json:"jsonrpc"`
    30  	Method    string          `json:"method"`
    31  	RawParams []Param         `json:"params,omitempty"`
    32  	RawID     json.RawMessage `json:"id,omitempty"`
    33  }
    34  
    35  // Batch represents a standard JSON-RPC 2.0
    36  // batch: https://www.jsonrpc.org/specification#batch.
    37  type Batch []In
    38  
    39  // MarshalJSON implements the json.Marshaler interface.
    40  func (r Request) MarshalJSON() ([]byte, error) {
    41  	if r.In != nil {
    42  		return json.Marshal(r.In)
    43  	}
    44  	return json.Marshal(r.Batch)
    45  }
    46  
    47  // UnmarshalJSON implements the json.Unmarshaler interface.
    48  func (r *Request) UnmarshalJSON(data []byte) error {
    49  	var (
    50  		in    *In
    51  		batch Batch
    52  	)
    53  	in = &In{}
    54  	err := json.Unmarshal(data, in)
    55  	if err == nil {
    56  		r.In = in
    57  		return nil
    58  	}
    59  	decoder := json.NewDecoder(bytes.NewReader(data))
    60  	t, err := decoder.Token() // read `[`
    61  	if err != nil {
    62  		return err
    63  	}
    64  	if t != json.Delim('[') {
    65  		return fmt.Errorf("`[` expected, got %s", t)
    66  	}
    67  	count := 0
    68  	for decoder.More() {
    69  		if count > maxBatchSize {
    70  			return fmt.Errorf("the number of requests in batch shouldn't exceed %d", maxBatchSize)
    71  		}
    72  		in = &In{}
    73  		decodeErr := decoder.Decode(in)
    74  		if decodeErr != nil {
    75  			return decodeErr
    76  		}
    77  		batch = append(batch, *in)
    78  		count++
    79  	}
    80  	if len(batch) == 0 {
    81  		return errors.New("empty request")
    82  	}
    83  	r.Batch = batch
    84  	return nil
    85  }
    86  
    87  // DecodeData decodes the given reader into the the request
    88  // struct.
    89  func (r *Request) DecodeData(data io.ReadCloser) error {
    90  	defer data.Close()
    91  
    92  	rawData := json.RawMessage{}
    93  	err := json.NewDecoder(data).Decode(&rawData)
    94  	if err != nil {
    95  		return fmt.Errorf("error parsing JSON payload: %w", err)
    96  	}
    97  
    98  	return r.UnmarshalJSON(rawData)
    99  }
   100  
   101  // NewRequest creates a new Request struct.
   102  func NewRequest() *Request {
   103  	return &Request{}
   104  }
   105  
   106  // NewIn creates a new In struct.
   107  func NewIn() *In {
   108  	return &In{
   109  		JSONRPC: neorpc.JSONRPCVersion,
   110  	}
   111  }