github.com/v2fly/tools@v0.100.0/internal/jsonrpc2/wire.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package jsonrpc2
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  )
    11  
    12  // this file contains the go forms of the wire specification
    13  // see http://www.jsonrpc.org/specification for details
    14  
    15  var (
    16  	// ErrUnknown should be used for all non coded errors.
    17  	ErrUnknown = NewError(-32001, "JSON RPC unknown error")
    18  	// ErrParse is used when invalid JSON was received by the server.
    19  	ErrParse = NewError(-32700, "JSON RPC parse error")
    20  	//ErrInvalidRequest is used when the JSON sent is not a valid Request object.
    21  	ErrInvalidRequest = NewError(-32600, "JSON RPC invalid request")
    22  	// ErrMethodNotFound should be returned by the handler when the method does
    23  	// not exist / is not available.
    24  	ErrMethodNotFound = NewError(-32601, "JSON RPC method not found")
    25  	// ErrInvalidParams should be returned by the handler when method
    26  	// parameter(s) were invalid.
    27  	ErrInvalidParams = NewError(-32602, "JSON RPC invalid params")
    28  	// ErrInternal is not currently returned but defined for completeness.
    29  	ErrInternal = NewError(-32603, "JSON RPC internal error")
    30  
    31  	//ErrServerOverloaded is returned when a message was refused due to a
    32  	//server being temporarily unable to accept any new messages.
    33  	ErrServerOverloaded = NewError(-32000, "JSON RPC overloaded")
    34  )
    35  
    36  // wireRequest is sent to a server to represent a Call or Notify operaton.
    37  type wireRequest struct {
    38  	// VersionTag is always encoded as the string "2.0"
    39  	VersionTag wireVersionTag `json:"jsonrpc"`
    40  	// Method is a string containing the method name to invoke.
    41  	Method string `json:"method"`
    42  	// Params is either a struct or an array with the parameters of the method.
    43  	Params *json.RawMessage `json:"params,omitempty"`
    44  	// The id of this request, used to tie the Response back to the request.
    45  	// Will be either a string or a number. If not set, the Request is a notify,
    46  	// and no response is possible.
    47  	ID *ID `json:"id,omitempty"`
    48  }
    49  
    50  // WireResponse is a reply to a Request.
    51  // It will always have the ID field set to tie it back to a request, and will
    52  // have either the Result or Error fields set depending on whether it is a
    53  // success or failure response.
    54  type wireResponse struct {
    55  	// VersionTag is always encoded as the string "2.0"
    56  	VersionTag wireVersionTag `json:"jsonrpc"`
    57  	// Result is the response value, and is required on success.
    58  	Result *json.RawMessage `json:"result,omitempty"`
    59  	// Error is a structured error response if the call fails.
    60  	Error *wireError `json:"error,omitempty"`
    61  	// ID must be set and is the identifier of the Request this is a response to.
    62  	ID *ID `json:"id,omitempty"`
    63  }
    64  
    65  // wireCombined has all the fields of both Request and Response.
    66  // We can decode this and then work out which it is.
    67  type wireCombined struct {
    68  	VersionTag wireVersionTag   `json:"jsonrpc"`
    69  	ID         *ID              `json:"id,omitempty"`
    70  	Method     string           `json:"method"`
    71  	Params     *json.RawMessage `json:"params,omitempty"`
    72  	Result     *json.RawMessage `json:"result,omitempty"`
    73  	Error      *wireError       `json:"error,omitempty"`
    74  }
    75  
    76  // wireError represents a structured error in a Response.
    77  type wireError struct {
    78  	// Code is an error code indicating the type of failure.
    79  	Code int64 `json:"code"`
    80  	// Message is a short description of the error.
    81  	Message string `json:"message"`
    82  	// Data is optional structured data containing additional information about the error.
    83  	Data *json.RawMessage `json:"data,omitempty"`
    84  }
    85  
    86  // wireVersionTag is a special 0 sized struct that encodes as the jsonrpc version
    87  // tag.
    88  // It will fail during decode if it is not the correct version tag in the
    89  // stream.
    90  type wireVersionTag struct{}
    91  
    92  // ID is a Request identifier.
    93  type ID struct {
    94  	name   string
    95  	number int64
    96  }
    97  
    98  func NewError(code int64, message string) error {
    99  	return &wireError{
   100  		Code:    code,
   101  		Message: message,
   102  	}
   103  }
   104  
   105  func (err *wireError) Error() string {
   106  	return err.Message
   107  }
   108  
   109  func (wireVersionTag) MarshalJSON() ([]byte, error) {
   110  	return json.Marshal("2.0")
   111  }
   112  
   113  func (wireVersionTag) UnmarshalJSON(data []byte) error {
   114  	version := ""
   115  	if err := json.Unmarshal(data, &version); err != nil {
   116  		return err
   117  	}
   118  	if version != "2.0" {
   119  		return fmt.Errorf("invalid RPC version %v", version)
   120  	}
   121  	return nil
   122  }
   123  
   124  // NewIntID returns a new numerical request ID.
   125  func NewIntID(v int64) ID { return ID{number: v} }
   126  
   127  // NewStringID returns a new string request ID.
   128  func NewStringID(v string) ID { return ID{name: v} }
   129  
   130  // Format writes the ID to the formatter.
   131  // If the rune is q the representation is non ambiguous,
   132  // string forms are quoted, number forms are preceded by a #
   133  func (id ID) Format(f fmt.State, r rune) {
   134  	numF, strF := `%d`, `%s`
   135  	if r == 'q' {
   136  		numF, strF = `#%d`, `%q`
   137  	}
   138  	switch {
   139  	case id.name != "":
   140  		fmt.Fprintf(f, strF, id.name)
   141  	default:
   142  		fmt.Fprintf(f, numF, id.number)
   143  	}
   144  }
   145  
   146  func (id *ID) MarshalJSON() ([]byte, error) {
   147  	if id.name != "" {
   148  		return json.Marshal(id.name)
   149  	}
   150  	return json.Marshal(id.number)
   151  }
   152  
   153  func (id *ID) UnmarshalJSON(data []byte) error {
   154  	*id = ID{}
   155  	if err := json.Unmarshal(data, &id.number); err == nil {
   156  		return nil
   157  	}
   158  	return json.Unmarshal(data, &id.name)
   159  }