forked from TrueCloudLab/neoneo-go
112 lines
2.4 KiB
Go
112 lines
2.4 KiB
Go
|
package params
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
|
||
|
"github.com/nspcc-dev/neo-go/pkg/rpc/request"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// maxBatchSize is the maximum number of requests per batch.
|
||
|
maxBatchSize = 100
|
||
|
)
|
||
|
|
||
|
// Request contains standard JSON-RPC 2.0 request and batch of
|
||
|
// requests: http://www.jsonrpc.org/specification.
|
||
|
// It's used in server to represent incoming queries.
|
||
|
type Request struct {
|
||
|
In *In
|
||
|
Batch Batch
|
||
|
}
|
||
|
|
||
|
// In represents a standard JSON-RPC 2.0
|
||
|
// request: http://www.jsonrpc.org/specification#request_object.
|
||
|
type In struct {
|
||
|
JSONRPC string `json:"jsonrpc"`
|
||
|
Method string `json:"method"`
|
||
|
RawParams []Param `json:"params,omitempty"`
|
||
|
RawID json.RawMessage `json:"id,omitempty"`
|
||
|
}
|
||
|
|
||
|
// Batch represents a standard JSON-RPC 2.0
|
||
|
// batch: https://www.jsonrpc.org/specification#batch.
|
||
|
type Batch []In
|
||
|
|
||
|
// MarshalJSON implements the json.Marshaler interface.
|
||
|
func (r Request) MarshalJSON() ([]byte, error) {
|
||
|
if r.In != nil {
|
||
|
return json.Marshal(r.In)
|
||
|
}
|
||
|
return json.Marshal(r.Batch)
|
||
|
}
|
||
|
|
||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||
|
func (r *Request) UnmarshalJSON(data []byte) error {
|
||
|
var (
|
||
|
in *In
|
||
|
batch Batch
|
||
|
)
|
||
|
in = &In{}
|
||
|
err := json.Unmarshal(data, in)
|
||
|
if err == nil {
|
||
|
r.In = in
|
||
|
return nil
|
||
|
}
|
||
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
||
|
t, err := decoder.Token() // read `[`
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if t != json.Delim('[') {
|
||
|
return fmt.Errorf("`[` expected, got %s", t)
|
||
|
}
|
||
|
count := 0
|
||
|
for decoder.More() {
|
||
|
if count > maxBatchSize {
|
||
|
return fmt.Errorf("the number of requests in batch shouldn't exceed %d", maxBatchSize)
|
||
|
}
|
||
|
in = &In{}
|
||
|
decodeErr := decoder.Decode(in)
|
||
|
if decodeErr != nil {
|
||
|
return decodeErr
|
||
|
}
|
||
|
batch = append(batch, *in)
|
||
|
count++
|
||
|
}
|
||
|
if len(batch) == 0 {
|
||
|
return errors.New("empty request")
|
||
|
}
|
||
|
r.Batch = batch
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// DecodeData decodes the given reader into the the request
|
||
|
// struct.
|
||
|
func (r *Request) DecodeData(data io.ReadCloser) error {
|
||
|
defer data.Close()
|
||
|
|
||
|
rawData := json.RawMessage{}
|
||
|
err := json.NewDecoder(data).Decode(&rawData)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("error parsing JSON payload: %w", err)
|
||
|
}
|
||
|
|
||
|
return r.UnmarshalJSON(rawData)
|
||
|
}
|
||
|
|
||
|
// NewRequest creates a new Request struct.
|
||
|
func NewRequest() *Request {
|
||
|
return &Request{}
|
||
|
}
|
||
|
|
||
|
// NewIn creates a new In struct.
|
||
|
func NewIn() *In {
|
||
|
return &In{
|
||
|
JSONRPC: request.JSONRPCVersion,
|
||
|
}
|
||
|
}
|