mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
updated json response to match spec by @davebryson
This commit is contained in:
parent
e0017c8a97
commit
60a1f49a5c
@ -2,7 +2,7 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
"github.com/tendermint/tendermint/rpc/lib/types"
|
rpctypes "github.com/tendermint/tendermint/rpc/lib/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ func Subscribe(wsCtx rpctypes.WSRPCContext, event string) (*ctypes.ResultSubscri
|
|||||||
// NOTE: EventSwitch callbacks must be nonblocking
|
// NOTE: EventSwitch callbacks must be nonblocking
|
||||||
// NOTE: RPCResponses of subscribed events have id suffix "#event"
|
// NOTE: RPCResponses of subscribed events have id suffix "#event"
|
||||||
tmResult := &ctypes.ResultEvent{event, msg}
|
tmResult := &ctypes.ResultEvent{event, msg}
|
||||||
wsCtx.TryWriteRPCResponse(rpctypes.NewRPCResponse(wsCtx.Request.ID+"#event", tmResult, ""))
|
wsCtx.TryWriteRPCResponse(rpctypes.NewRPCSuccessResponse(wsCtx.Request.ID+"#event", tmResult))
|
||||||
})
|
})
|
||||||
return &ctypes.ResultSubscribe{}, nil
|
return &ctypes.ResultSubscribe{}, nil
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Errorf("Error unmarshalling rpc response: %v", err)
|
return nil, errors.Errorf("Error unmarshalling rpc response: %v", err)
|
||||||
}
|
}
|
||||||
errorStr := response.Error
|
errorStr := response.Error.Message
|
||||||
if errorStr != "" {
|
if errorStr != "" {
|
||||||
return nil, errors.Errorf("Response error: %v", errorStr)
|
return nil, errors.Errorf("Response error: %v", errorStr)
|
||||||
}
|
}
|
||||||
|
@ -110,35 +110,35 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han
|
|||||||
var request types.RPCRequest
|
var request types.RPCRequest
|
||||||
err := json.Unmarshal(b, &request)
|
err := json.Unmarshal(b, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusBadRequest, types.NewRPCResponse("", nil, fmt.Sprintf("Error unmarshalling request: %v", err.Error())))
|
WriteRPCResponseHTTP(w, types.RPCParseError(""))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(r.URL.Path) > 1 {
|
if len(r.URL.Path) > 1 {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusNotFound, types.NewRPCResponse(request.ID, nil, fmt.Sprintf("Invalid JSONRPC endpoint %s", r.URL.Path)))
|
WriteRPCResponseHTTP(w, types.RPCInvalidRequestError(request.ID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rpcFunc := funcMap[request.Method]
|
rpcFunc := funcMap[request.Method]
|
||||||
if rpcFunc == nil {
|
if rpcFunc == nil {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusNotFound, types.NewRPCResponse(request.ID, nil, "RPC method unknown: "+request.Method))
|
WriteRPCResponseHTTP(w, types.RPCMethodNotFoundError(request.ID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if rpcFunc.ws {
|
if rpcFunc.ws {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusMethodNotAllowed, types.NewRPCResponse(request.ID, nil, "RPC method is only for websockets: "+request.Method))
|
WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
args, err := jsonParamsToArgsRPC(rpcFunc, request.Params)
|
args, err := jsonParamsToArgsRPC(rpcFunc, request.Params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusBadRequest, types.NewRPCResponse(request.ID, nil, fmt.Sprintf("Error converting json params to arguments: %v", err.Error())))
|
WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(request.ID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
returns := rpcFunc.f.Call(args)
|
returns := rpcFunc.f.Call(args)
|
||||||
logger.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns)
|
logger.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns)
|
||||||
result, err := unreflectResult(returns)
|
result, err := unreflectResult(returns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusInternalServerError, types.NewRPCResponse(request.ID, result, err.Error()))
|
WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
WriteRPCResponseHTTP(w, types.NewRPCResponse(request.ID, result, ""))
|
WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(request.ID, result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit
|
|||||||
// Exception for websocket endpoints
|
// Exception for websocket endpoints
|
||||||
if rpcFunc.ws {
|
if rpcFunc.ws {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusMethodNotAllowed, types.NewRPCResponse("", nil, "This RPC method is only for websockets"))
|
WriteRPCResponseHTTP(w, types.RPCInternalError(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// All other endpoints
|
// All other endpoints
|
||||||
@ -237,17 +237,17 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit
|
|||||||
logger.Debug("HTTP HANDLER", "req", r)
|
logger.Debug("HTTP HANDLER", "req", r)
|
||||||
args, err := httpParamsToArgs(rpcFunc, r)
|
args, err := httpParamsToArgs(rpcFunc, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusBadRequest, types.NewRPCResponse("", nil, fmt.Sprintf("Error converting http params to args: %v", err.Error())))
|
WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(""))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
returns := rpcFunc.f.Call(args)
|
returns := rpcFunc.f.Call(args)
|
||||||
logger.Info("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns)
|
logger.Info("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns)
|
||||||
result, err := unreflectResult(returns)
|
result, err := unreflectResult(returns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
WriteRPCResponseHTTPError(w, http.StatusInternalServerError, types.NewRPCResponse("", nil, err.Error()))
|
WriteRPCResponseHTTP(w, types.RPCInternalError(""))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
WriteRPCResponseHTTP(w, types.NewRPCResponse("", result, ""))
|
WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse("", result))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,8 +509,7 @@ func (wsc *wsConnection) readRoutine() {
|
|||||||
var request types.RPCRequest
|
var request types.RPCRequest
|
||||||
err = json.Unmarshal(in, &request)
|
err = json.Unmarshal(in, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errStr := fmt.Sprintf("Error unmarshaling data: %s", err.Error())
|
wsc.WriteRPCResponse(types.RPCParseError(""))
|
||||||
wsc.WriteRPCResponse(types.NewRPCResponse(request.ID, nil, errStr))
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +517,7 @@ func (wsc *wsConnection) readRoutine() {
|
|||||||
|
|
||||||
rpcFunc := wsc.funcMap[request.Method]
|
rpcFunc := wsc.funcMap[request.Method]
|
||||||
if rpcFunc == nil {
|
if rpcFunc == nil {
|
||||||
wsc.WriteRPCResponse(types.NewRPCResponse(request.ID, nil, "RPC method unknown: "+request.Method))
|
wsc.WriteRPCResponse(types.RPCMethodNotFoundError(request.ID))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var args []reflect.Value
|
var args []reflect.Value
|
||||||
@ -529,7 +528,7 @@ func (wsc *wsConnection) readRoutine() {
|
|||||||
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wsc.WriteRPCResponse(types.NewRPCResponse(request.ID, nil, err.Error()))
|
wsc.WriteRPCResponse(types.RPCInternalError(request.ID))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
returns := rpcFunc.f.Call(args)
|
returns := rpcFunc.f.Call(args)
|
||||||
@ -539,10 +538,10 @@ func (wsc *wsConnection) readRoutine() {
|
|||||||
|
|
||||||
result, err := unreflectResult(returns)
|
result, err := unreflectResult(returns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wsc.WriteRPCResponse(types.NewRPCResponse(request.ID, nil, err.Error()))
|
wsc.WriteRPCResponse(types.RPCInternalError(request.ID))
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
wsc.WriteRPCResponse(types.NewRPCResponse(request.ID, result, ""))
|
wsc.WriteRPCResponse(types.NewRPCSuccessResponse(request.ID, result))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler
|
|||||||
// For the rest,
|
// For the rest,
|
||||||
logger.Error("Panic in RPC HTTP handler", "err", e, "stack", string(debug.Stack()))
|
logger.Error("Panic in RPC HTTP handler", "err", e, "stack", string(debug.Stack()))
|
||||||
rww.WriteHeader(http.StatusInternalServerError)
|
rww.WriteHeader(http.StatusInternalServerError)
|
||||||
WriteRPCResponseHTTP(rww, types.NewRPCResponse("", nil, fmt.Sprintf("Internal Server Error: %v", e)))
|
WriteRPCResponseHTTP(rww, types.RPCInternalError(""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,11 @@ import (
|
|||||||
events "github.com/tendermint/tmlibs/events"
|
events "github.com/tendermint/tmlibs/events"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RpcError struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
type RPCRequest struct {
|
type RPCRequest struct {
|
||||||
JSONRPC string `json:"jsonrpc"`
|
JSONRPC string `json:"jsonrpc"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
@ -50,28 +55,32 @@ func ArrayToRequest(id string, method string, params []interface{}) (RPCRequest,
|
|||||||
|
|
||||||
type RPCResponse struct {
|
type RPCResponse struct {
|
||||||
JSONRPC string `json:"jsonrpc"`
|
JSONRPC string `json:"jsonrpc"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id,omitempty"`
|
||||||
Result *json.RawMessage `json:"result"`
|
Result *json.RawMessage `json:"result,omitempty"`
|
||||||
Error string `json:"error"`
|
Error *RpcError `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRPCResponse(id string, res interface{}, err string) RPCResponse {
|
func NewRPCSuccessResponse(id string, res interface{}) RPCResponse {
|
||||||
var raw *json.RawMessage
|
var raw *json.RawMessage
|
||||||
|
|
||||||
if res != nil {
|
if res != nil {
|
||||||
var js []byte
|
var js []byte
|
||||||
js, err2 := json.Marshal(res)
|
js, err := json.Marshal(res)
|
||||||
if err2 == nil {
|
if err != nil {
|
||||||
|
return RPCInternalError(id)
|
||||||
|
}
|
||||||
rawMsg := json.RawMessage(js)
|
rawMsg := json.RawMessage(js)
|
||||||
raw = &rawMsg
|
raw = &rawMsg
|
||||||
} else {
|
|
||||||
err = err2.Error()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return RPCResponse{JSONRPC: "2.0", ID: id, Result: raw}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRPCErrorResponse(id string, code int, msg string) RPCResponse {
|
||||||
return RPCResponse{
|
return RPCResponse{
|
||||||
JSONRPC: "2.0",
|
JSONRPC: "2.0",
|
||||||
ID: id,
|
ID: id,
|
||||||
Result: raw,
|
Error: &RpcError{Code: code, Message: msg},
|
||||||
Error: err,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +92,30 @@ func (resp RPCResponse) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RPCParseError(id string) RPCResponse {
|
||||||
|
return NewRPCErrorResponse(id, -32700, "Parse error. Invalid JSON")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RPCInvalidRequestError(id string) RPCResponse {
|
||||||
|
return NewRPCErrorResponse(id, -32600, "Invalid Request")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RPCMethodNotFoundError(id string) RPCResponse {
|
||||||
|
return NewRPCErrorResponse(id, -32601, "Method not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RPCInvalidParamsError(id string) RPCResponse {
|
||||||
|
return NewRPCErrorResponse(id, -32602, "Invalid params")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RPCInternalError(id string) RPCResponse {
|
||||||
|
return NewRPCErrorResponse(id, -32603, "Internal error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func RPCServerError(id string) RPCResponse {
|
||||||
|
return NewRPCErrorResponse(id, -32000, "Server error")
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
|
||||||
// *wsConnection implements this interface.
|
// *wsConnection implements this interface.
|
||||||
|
32
rpc/lib/types/types_test.go
Normal file
32
rpc/lib/types/types_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package rpctypes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SampleResult struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResponses(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
a := NewRPCSuccessResponse("1", &SampleResult{"hello"})
|
||||||
|
b, _ := json.Marshal(a)
|
||||||
|
s := `{"jsonrpc":"2.0","id":"1","result":{"Value":"hello"}}`
|
||||||
|
assert.Equal(string(s), string(b))
|
||||||
|
|
||||||
|
d := RPCParseError("1")
|
||||||
|
e, _ := json.Marshal(d)
|
||||||
|
f := `{"jsonrpc":"2.0","id":"1","error":{"code":-32700,"message":"Parse error. Invalid JSON"}}`
|
||||||
|
assert.Equal(string(f), string(e))
|
||||||
|
|
||||||
|
g := RPCMethodNotFoundError("2")
|
||||||
|
h, _ := json.Marshal(g)
|
||||||
|
i := `{"jsonrpc":"2.0","id":"2","error":{"code":-32601,"message":"Method not found"}}`
|
||||||
|
assert.Equal(string(h), string(i))
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user