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