| 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 operation. |
| 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 | } |
| 160 |
Members