OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / btcsuite / btcd / btcjson / jsonrpc.go
1 // Copyright (c) 2014 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4
5 package btcjson
6
7 import (
8         "encoding/json"
9         "fmt"
10 )
11
12 // RPCErrorCode represents an error code to be used as a part of an RPCError
13 // which is in turn used in a JSON-RPC Response object.
14 //
15 // A specific type is used to help ensure the wrong errors aren't used.
16 type RPCErrorCode int
17
18 // RPCError represents an error that is used as a part of a JSON-RPC Response
19 // object.
20 type RPCError struct {
21         Code    RPCErrorCode `json:"code,omitempty"`
22         Message string       `json:"message,omitempty"`
23 }
24
25 // Guarantee RPCError satisifies the builtin error interface.
26 var _, _ error = RPCError{}, (*RPCError)(nil)
27
28 // Error returns a string describing the RPC error.  This satisifies the
29 // builtin error interface.
30 func (e RPCError) Error() string {
31         return fmt.Sprintf("%d: %s", e.Code, e.Message)
32 }
33
34 // NewRPCError constructs and returns a new JSON-RPC error that is suitable
35 // for use in a JSON-RPC Response object.
36 func NewRPCError(code RPCErrorCode, message string) *RPCError {
37         return &RPCError{
38                 Code:    code,
39                 Message: message,
40         }
41 }
42
43 // IsValidIDType checks that the ID field (which can go in any of the JSON-RPC
44 // requests, responses, or notifications) is valid.  JSON-RPC 1.0 allows any
45 // valid JSON type.  JSON-RPC 2.0 (which bitcoind follows for some parts) only
46 // allows string, number, or null, so this function restricts the allowed types
47 // to that list.  This function is only provided in case the caller is manually
48 // marshalling for some reason.    The functions which accept an ID in this
49 // package already call this function to ensure the provided id is valid.
50 func IsValidIDType(id interface{}) bool {
51         switch id.(type) {
52         case int, int8, int16, int32, int64,
53                 uint, uint8, uint16, uint32, uint64,
54                 float32, float64,
55                 string,
56                 nil:
57                 return true
58         default:
59                 return false
60         }
61 }
62
63 // Request is a type for raw JSON-RPC 1.0 requests.  The Method field identifies
64 // the specific command type which in turns leads to different parameters.
65 // Callers typically will not use this directly since this package provides a
66 // statically typed command infrastructure which handles creation of these
67 // requests, however this struct it being exported in case the caller wants to
68 // construct raw requests for some reason.
69 type Request struct {
70         Jsonrpc string            `json:"jsonrpc"`
71         Method  string            `json:"method"`
72         Params  []json.RawMessage `json:"params"`
73         ID      interface{}       `json:"id"`
74 }
75
76 // NewRequest returns a new JSON-RPC 1.0 request object given the provided id,
77 // method, and parameters.  The parameters are marshalled into a json.RawMessage
78 // for the Params field of the returned request object.  This function is only
79 // provided in case the caller wants to construct raw requests for some reason.
80 //
81 // Typically callers will instead want to create a registered concrete command
82 // type with the NewCmd or New<Foo>Cmd functions and call the MarshalCmd
83 // function with that command to generate the marshalled JSON-RPC request.
84 func NewRequest(id interface{}, method string, params []interface{}) (*Request, error) {
85         if !IsValidIDType(id) {
86                 str := fmt.Sprintf("the id of type '%T' is invalid", id)
87                 return nil, makeError(ErrInvalidType, str)
88         }
89
90         rawParams := make([]json.RawMessage, 0, len(params))
91         for _, param := range params {
92                 marshalledParam, err := json.Marshal(param)
93                 if err != nil {
94                         return nil, err
95                 }
96                 rawMessage := json.RawMessage(marshalledParam)
97                 rawParams = append(rawParams, rawMessage)
98         }
99
100         return &Request{
101                 Jsonrpc: "1.0",
102                 ID:      id,
103                 Method:  method,
104                 Params:  rawParams,
105         }, nil
106 }
107
108 // Response is the general form of a JSON-RPC response.  The type of the Result
109 // field varies from one command to the next, so it is implemented as an
110 // interface.  The ID field has to be a pointer for Go to put a null in it when
111 // empty.
112 type Response struct {
113         Result json.RawMessage `json:"result"`
114         Error  *RPCError       `json:"error"`
115         ID     *interface{}    `json:"id"`
116 }
117
118 // NewResponse returns a new JSON-RPC response object given the provided id,
119 // marshalled result, and RPC error.  This function is only provided in case the
120 // caller wants to construct raw responses for some reason.
121 //
122 // Typically callers will instead want to create the fully marshalled JSON-RPC
123 // response to send over the wire with the MarshalResponse function.
124 func NewResponse(id interface{}, marshalledResult []byte, rpcErr *RPCError) (*Response, error) {
125         if !IsValidIDType(id) {
126                 str := fmt.Sprintf("the id of type '%T' is invalid", id)
127                 return nil, makeError(ErrInvalidType, str)
128         }
129
130         pid := &id
131         return &Response{
132                 Result: marshalledResult,
133                 Error:  rpcErr,
134                 ID:     pid,
135         }, nil
136 }
137
138 // MarshalResponse marshals the passed id, result, and RPCError to a JSON-RPC
139 // response byte slice that is suitable for transmission to a JSON-RPC client.
140 func MarshalResponse(id interface{}, result interface{}, rpcErr *RPCError) ([]byte, error) {
141         marshalledResult, err := json.Marshal(result)
142         if err != nil {
143                 return nil, err
144         }
145         response, err := NewResponse(id, marshalledResult, rpcErr)
146         if err != nil {
147                 return nil, err
148         }
149         return json.Marshal(&response)
150 }