--- /dev/null
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jsonrpc2
+
+import (
+ "encoding/json"
+ "fmt"
+ "math"
+)
+
+// this file contains the go forms of the wire specification
+// see http://www.jsonrpc.org/specification for details
+
+var (
+ // ErrUnknown should be used for all non coded errors.
+ ErrUnknown = NewError(-32001, "JSON RPC unknown error")
+ // ErrParse is used when invalid JSON was received by the server.
+ ErrParse = NewError(-32700, "JSON RPC parse error")
+ //ErrInvalidRequest is used when the JSON sent is not a valid Request object.
+ ErrInvalidRequest = NewError(-32600, "JSON RPC invalid request")
+ // ErrMethodNotFound should be returned by the handler when the method does
+ // not exist / is not available.
+ ErrMethodNotFound = NewError(-32601, "JSON RPC method not found")
+ // ErrInvalidParams should be returned by the handler when method
+ // parameter(s) were invalid.
+ ErrInvalidParams = NewError(-32602, "JSON RPC invalid params")
+ // ErrInternal is not currently returned but defined for completeness.
+ ErrInternal = NewError(-32603, "JSON RPC internal error")
+
+ //ErrServerOverloaded is returned when a message was refused due to a
+ //server being temporarily unable to accept any new messages.
+ ErrServerOverloaded = NewError(-32000, "JSON RPC overloaded")
+)
+
+// wireRequest is sent to a server to represent a Call or Notify operaton.
+type wireRequest struct {
+ // VersionTag is always encoded as the string "2.0"
+ VersionTag wireVersionTag `json:"jsonrpc"`
+ // Method is a string containing the method name to invoke.
+ Method string `json:"method"`
+ // Params is either a struct or an array with the parameters of the method.
+ Params *json.RawMessage `json:"params,omitempty"`
+ // The id of this request, used to tie the Response back to the request.
+ // Will be either a string or a number. If not set, the Request is a notify,
+ // and no response is possible.
+ ID *ID `json:"id,omitempty"`
+}
+
+// WireResponse is a reply to a Request.
+// It will always have the ID field set to tie it back to a request, and will
+// have either the Result or Error fields set depending on whether it is a
+// success or failure response.
+type wireResponse struct {
+ // VersionTag is always encoded as the string "2.0"
+ VersionTag wireVersionTag `json:"jsonrpc"`
+ // Result is the response value, and is required on success.
+ Result *json.RawMessage `json:"result,omitempty"`
+ // Error is a structured error response if the call fails.
+ Error *wireError `json:"error,omitempty"`
+ // ID must be set and is the identifier of the Request this is a response to.
+ ID *ID `json:"id,omitempty"`
+}
+
+// wireCombined has all the fields of both Request and Response.
+// We can decode this and then work out which it is.
+type wireCombined struct {
+ VersionTag wireVersionTag `json:"jsonrpc"`
+ ID *ID `json:"id,omitempty"`
+ Method string `json:"method"`
+ Params *json.RawMessage `json:"params,omitempty"`
+ Result *json.RawMessage `json:"result,omitempty"`
+ Error *wireError `json:"error,omitempty"`
+}
+
+// wireError represents a structured error in a Response.
+type wireError struct {
+ // Code is an error code indicating the type of failure.
+ Code int64 `json:"code"`
+ // Message is a short description of the error.
+ Message string `json:"message"`
+ // Data is optional structured data containing additional information about the error.
+ Data *json.RawMessage `json:"data,omitempty"`
+}
+
+// wireVersionTag is a special 0 sized struct that encodes as the jsonrpc version
+// tag.
+// It will fail during decode if it is not the correct version tag in the
+// stream.
+type wireVersionTag struct{}
+
+// ID is a Request identifier.
+type ID struct {
+ name string
+ number int64
+}
+
+func NewError(code int64, message string) error {
+ return &wireError{
+ Code: code,
+ Message: message,
+ }
+}
+
+func (err *wireError) Error() string {
+ return err.Message
+}
+
+func (wireVersionTag) MarshalJSON() ([]byte, error) {
+ return json.Marshal("2.0")
+}
+
+func (wireVersionTag) UnmarshalJSON(data []byte) error {
+ version := ""
+ if err := json.Unmarshal(data, &version); err != nil {
+ return err
+ }
+ if version != "2.0" {
+ return fmt.Errorf("invalid RPC version %v", version)
+ }
+ return nil
+}
+
+const invalidID int64 = math.MaxInt64
+
+// NewIntID returns a new numerical request ID.
+func NewIntID(v int64) ID { return ID{number: v} }
+
+// NewStringID returns a new string request ID.
+func NewStringID(v string) ID { return ID{name: v} }
+
+// Format writes the ID to the formatter.
+// If the rune is q the representation is non ambiguous,
+// string forms are quoted, number forms are preceded by a #
+func (id ID) Format(f fmt.State, r rune) {
+ numF, strF := `%d`, `%s`
+ if r == 'q' {
+ numF, strF = `#%d`, `%q`
+ }
+ switch {
+ case id.name != "":
+ fmt.Fprintf(f, strF, id.name)
+ default:
+ fmt.Fprintf(f, numF, id.number)
+ }
+}
+
+func (id *ID) MarshalJSON() ([]byte, error) {
+ if id.name != "" {
+ return json.Marshal(id.name)
+ }
+ return json.Marshal(id.number)
+}
+
+func (id *ID) UnmarshalJSON(data []byte) error {
+ *id = ID{}
+ if err := json.Unmarshal(data, &id.number); err == nil {
+ return nil
+ }
+ return json.Unmarshal(data, &id.name)
+}