1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
// Package jsonrpc2 provides a client and server implementation of
// [JSON-RPC 2.0](http://www.jsonrpc.org/specification).
package jsonrpc2
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
)
// JSONRPC2 describes an interface for issuing requests that speak the
// JSON-RPC 2 protocol. It isn't really necessary for this package
// itself, but is useful for external users that use the interface as
// an API boundary.
type JSONRPC2 interface {
// Call issues a standard request (http://www.jsonrpc.org/specification#request_object).
Call(ctx context.Context, method string, params, result interface{}, opt ...CallOption) error
// Notify issues a notification request (http://www.jsonrpc.org/specification#notification).
Notify(ctx context.Context, method string, params interface{}, opt ...CallOption) error
// Close closes the underlying connection, if it exists.
Close() error
}
// Error represents a JSON-RPC response error.
type Error struct {
Code int64 `json:"code"`
Message string `json:"message"`
Data *json.RawMessage `json:"data,omitempty"`
}
// SetError sets e.Data to the JSON encoding of v. If JSON
// marshaling fails, it panics.
func (e *Error) SetError(v interface{}) {
b, err := json.Marshal(v)
if err != nil {
panic("Error.SetData: " + err.Error())
}
e.Data = (*json.RawMessage)(&b)
}
// Error implements the Go error interface.
func (e *Error) Error() string {
return fmt.Sprintf("jsonrpc2: code %v message: %s", e.Code, e.Message)
}
// Errors defined in the JSON-RPC spec. See
// http://www.jsonrpc.org/specification#error_object.
const (
CodeParseError = -32700
CodeInvalidRequest = -32600
CodeMethodNotFound = -32601
CodeInvalidParams = -32602
CodeInternalError = -32603
)
// Handler handles JSON-RPC requests and notifications.
type Handler interface {
// Handle is called to handle a request. No other requests are handled
// until it returns. If you do not require strict ordering behavior
// of received RPCs, it is suggested to wrap your handler in
// AsyncHandler.
Handle(context.Context, *Conn, *Request)
}
// ID represents a JSON-RPC 2.0 request ID, which may be either a
// string or number (or null, which is unsupported).
type ID struct {
// At most one of Num or Str may be nonzero. If both are zero
// valued, then IsNum specifies which field's value is to be used
// as the ID.
Num uint64
Str string
// IsString controls whether the Num or Str field's value should be
// used as the ID, when both are zero valued. It must always be
// set to true if the request ID is a string.
IsString bool
}
func (id ID) String() string {
if id.IsString {
return strconv.Quote(id.Str)
}
return strconv.FormatUint(id.Num, 10)
}
// MarshalJSON implements json.Marshaler.
func (id ID) MarshalJSON() ([]byte, error) {
if id.IsString {
return json.Marshal(id.Str)
}
return json.Marshal(id.Num)
}
// UnmarshalJSON implements json.Unmarshaler.
func (id *ID) UnmarshalJSON(data []byte) error {
// Support both uint64 and string IDs.
var v uint64
if err := json.Unmarshal(data, &v); err == nil {
*id = ID{Num: v}
return nil
}
var v2 string
if err := json.Unmarshal(data, &v2); err != nil {
return err
}
*id = ID{Str: v2, IsString: true}
return nil
}
// ErrClosed indicates that the JSON-RPC connection is closed (or in
// the process of closing).
var ErrClosed = errors.New("jsonrpc2: connection is closed")
var jsonNull = json.RawMessage("null")
|