forked from hyperledger-archives/burrow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.go
190 lines (161 loc) · 5.02 KB
/
types.go
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package types
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/pkg/errors"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
)
//----------------------------------------
// REQUEST
type RPCRequest struct {
JSONRPC string `json:"jsonrpc"`
ID string `json:"id"`
Method string `json:"method"`
Params json.RawMessage `json:"params"` // must be map[string]interface{} or []interface{}
}
func NewRPCRequest(id string, method string, params json.RawMessage) RPCRequest {
return RPCRequest{
JSONRPC: "2.0",
ID: id,
Method: method,
Params: params,
}
}
func (req RPCRequest) String() string {
return fmt.Sprintf("[%s %s]", req.ID, req.Method)
}
func MapToRequest(id string, method string, params map[string]interface{}) (RPCRequest, error) {
var params_ = make(map[string]json.RawMessage, len(params))
for name, value := range params {
valueJSON, err := json.Marshal(value)
if err != nil {
return RPCRequest{}, err
}
params_[name] = valueJSON
}
payload, err := json.Marshal(params_) // NOTE: Amino doesn't handle maps yet.
if err != nil {
return RPCRequest{}, err
}
request := NewRPCRequest(id, method, payload)
return request, nil
}
func ArrayToRequest(id string, method string, params []interface{}) (RPCRequest, error) {
var params_ = make([]json.RawMessage, len(params))
for i, value := range params {
valueJSON, err := json.Marshal(value)
if err != nil {
return RPCRequest{}, err
}
params_[i] = valueJSON
}
payload, err := json.Marshal(params_) // NOTE: Amino doesn't handle maps yet.
if err != nil {
return RPCRequest{}, err
}
request := NewRPCRequest(id, method, payload)
return request, nil
}
//----------------------------------------
// RESPONSE
type RPCError struct {
Code RPCErrorCode `json:"code"`
Message string `json:"message"`
Data string `json:"data,omitempty"`
}
func (err RPCError) Error() string {
const baseFormat = "RPC error %v - %s"
if err.Data != "" {
return fmt.Sprintf(baseFormat+": %s", err.Code, err.Message, err.Data)
}
return fmt.Sprintf(baseFormat, err.Code, err.Message)
}
func (err *RPCError) HTTPStatusCode() int {
if err == nil {
return 200
}
return err.Code.HTTPStatusCode()
}
type RPCResponse struct {
JSONRPC string `json:"jsonrpc"`
ID string `json:"id"`
Result json.RawMessage `json:"result,omitempty"`
Error *RPCError `json:"error,omitempty"`
}
func NewRPCSuccessResponse(id string, res interface{}) RPCResponse {
var rawMsg json.RawMessage
if res != nil {
var js []byte
js, err := json.Marshal(res)
if err != nil {
return RPCInternalError(id, errors.Wrap(err, "Error marshalling response"))
}
rawMsg = json.RawMessage(js)
}
return RPCResponse{JSONRPC: "2.0", ID: id, Result: rawMsg}
}
func NewRPCErrorResponse(id string, code RPCErrorCode, data string) RPCResponse {
return RPCResponse{
JSONRPC: "2.0",
ID: id,
Error: &RPCError{Code: code, Message: code.String(), Data: data},
}
}
func (resp RPCResponse) String() string {
if resp.Error == nil {
return fmt.Sprintf("[%s %v]", resp.ID, resp.Result)
}
return fmt.Sprintf("[%s %s]", resp.ID, resp.Error)
}
func RPCParseError(id string, err error) RPCResponse {
return NewRPCErrorResponse(id, RPCErrorCodeParseError, err.Error())
}
func RPCInvalidRequestError(id string, err error) RPCResponse {
return NewRPCErrorResponse(id, RPCErrorCodeInvalidRequest, err.Error())
}
func RPCMethodNotFoundError(id string) RPCResponse {
return NewRPCErrorResponse(id, RPCErrorCodeMethodNotFound, "")
}
func RPCInvalidParamsError(id string, err error) RPCResponse {
return NewRPCErrorResponse(id, RPCErrorCodeInvalidParams, err.Error())
}
func RPCInternalError(id string, err error) RPCResponse {
return NewRPCErrorResponse(id, RPCErrorCodeInternalError, err.Error())
}
func RPCServerError(id string, err error) RPCResponse {
return NewRPCErrorResponse(id, RPCErrorCodeServerError, err.Error())
}
//----------------------------------------
// *wsConnection implements this interface.
type WSRPCConnection interface {
GetRemoteAddr() string
WriteRPCResponse(resp RPCResponse)
TryWriteRPCResponse(resp RPCResponse) bool
GetEventSubscriber() EventSubscriber
}
// EventSubscriber mirros tendermint/tendermint/types.EventBusSubscriber
type EventSubscriber interface {
Subscribe(ctx context.Context, subscriber string, query tmpubsub.Query, out chan<- interface{}) error
Unsubscribe(ctx context.Context, subscriber string, query tmpubsub.Query) error
UnsubscribeAll(ctx context.Context, subscriber string) error
}
// websocket-only RPCFuncs take this as the first parameter.
type WSRPCContext struct {
Request RPCRequest
WSRPCConnection
}
//----------------------------------------
// SOCKETS
//
// Determine if its a unix or tcp socket.
// If tcp, must specify the port; `0.0.0.0` will return incorrectly as "unix" since there's no port
// TODO: deprecate
func SocketType(listenAddr string) string {
socketType := "unix"
if len(strings.Split(listenAddr, ":")) >= 2 {
socketType = "tcp"
}
return socketType
}