Browse Source

RPCResponse.Result is json.RawMessage

pull/456/head
Ethan Buchman 9 years ago
parent
commit
aff561d8c3
5 changed files with 44 additions and 28 deletions
  1. +14
    -11
      client/http_client.go
  2. +2
    -2
      client/ws_client.go
  3. +11
    -7
      server/handlers.go
  4. +7
    -2
      server/http_server.go
  5. +10
    -6
      types/types.go

+ 14
- 11
client/http_client.go View File

@ -2,6 +2,7 @@ package rpcclient
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@ -22,8 +23,8 @@ func NewClientJSONRPC(remote string) *ClientJSONRPC {
return &ClientJSONRPC{remote} return &ClientJSONRPC{remote}
} }
func (c *ClientJSONRPC) Call(method string, params []interface{}) (interface{}, error) {
return CallHTTP_JSONRPC(c.remote, method, params)
func (c *ClientJSONRPC) Call(method string, params []interface{}, result interface{}) (interface{}, error) {
return CallHTTP_JSONRPC(c.remote, method, params, result)
} }
// URI takes params as a map // URI takes params as a map
@ -38,11 +39,11 @@ func NewClientURI(remote string) *ClientURI {
return &ClientURI{remote} return &ClientURI{remote}
} }
func (c *ClientURI) Call(method string, params map[string]interface{}) (interface{}, error) {
return CallHTTP_URI(c.remote, method, params)
func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
return CallHTTP_URI(c.remote, method, params, result)
} }
func CallHTTP_JSONRPC(remote string, method string, params []interface{}) (interface{}, error) {
func CallHTTP_JSONRPC(remote string, method string, params []interface{}, result interface{}) (interface{}, error) {
// Make request and get responseBytes // Make request and get responseBytes
request := rpctypes.RPCRequest{ request := rpctypes.RPCRequest{
JSONRPC: "2.0", JSONRPC: "2.0",
@ -63,10 +64,10 @@ func CallHTTP_JSONRPC(remote string, method string, params []interface{}) (inter
return nil, err return nil, err
} }
log.Info(Fmt("RPC response: %v", string(responseBytes))) log.Info(Fmt("RPC response: %v", string(responseBytes)))
return unmarshalResponseBytes(responseBytes)
return unmarshalResponseBytes(responseBytes, result)
} }
func CallHTTP_URI(remote string, method string, params map[string]interface{}) (interface{}, error) {
func CallHTTP_URI(remote string, method string, params map[string]interface{}, result interface{}) (interface{}, error) {
values, err := argsToURLValues(params) values, err := argsToURLValues(params)
if err != nil { if err != nil {
return nil, err return nil, err
@ -81,18 +82,18 @@ func CallHTTP_URI(remote string, method string, params map[string]interface{}) (
if err != nil { if err != nil {
return nil, err return nil, err
} }
return unmarshalResponseBytes(responseBytes)
return unmarshalResponseBytes(responseBytes, result)
} }
//------------------------------------------------ //------------------------------------------------
func unmarshalResponseBytes(responseBytes []byte) (interface{}, error) {
func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
// read response // read response
// if rpc/core/types is imported, the result will unmarshal // if rpc/core/types is imported, the result will unmarshal
// into the correct type // into the correct type
var err error var err error
response := &rpctypes.RPCResponse{} response := &rpctypes.RPCResponse{}
wire.ReadJSON(response, responseBytes, &err)
err = json.Unmarshal(responseBytes, response)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -100,7 +101,9 @@ func unmarshalResponseBytes(responseBytes []byte) (interface{}, error) {
if errorStr != "" { if errorStr != "" {
return nil, errors.New(errorStr) return nil, errors.New(errorStr)
} }
return response.Result, err
// unmarshal the RawMessage into the result
result = wire.ReadJSONPtr(result, *response.Result, &err)
return result, err
} }
func argsToURLValues(args map[string]interface{}) (url.Values, error) { func argsToURLValues(args map[string]interface{}) (url.Values, error) {


+ 2
- 2
client/ws_client.go View File

@ -1,13 +1,13 @@
package rpcclient package rpcclient
import ( import (
"encoding/json"
"net/http" "net/http"
"time" "time"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
. "github.com/tendermint/go-common" . "github.com/tendermint/go-common"
"github.com/tendermint/go-rpc/types" "github.com/tendermint/go-rpc/types"
"github.com/tendermint/go-wire"
) )
const ( const (
@ -79,7 +79,7 @@ func (wsc *WSClient) receiveEventsRoutine() {
break break
} else { } else {
var response rpctypes.RPCResponse var response rpctypes.RPCResponse
wire.ReadJSON(&response, data, &err)
err := json.Unmarshal(data, &response)
if err != nil { if err != nil {
log.Info("WSClient failed to parse message", "error", err, "data", string(data)) log.Info("WSClient failed to parse message", "error", err, "data", string(data))
wsc.Stop() wsc.Stop()


+ 11
- 7
server/handlers.go View File

@ -19,6 +19,8 @@ import (
"github.com/tendermint/go-wire" "github.com/tendermint/go-wire"
) )
// Adds a route for each function in the funcMap, as well as general jsonrpc and websocket handlers for all functions.
// "result" is the interface on which the result objects are registered, and is popualted with every RPCResponse
func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) { func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) {
// HTTP endpoints // HTTP endpoints
for funcName, rpcFunc := range funcMap { for funcName, rpcFunc := range funcMap {
@ -433,7 +435,6 @@ func (wsc *wsConnection) readRoutine() {
// receives on a write channel and writes out on the socket // receives on a write channel and writes out on the socket
func (wsc *wsConnection) writeRoutine() { func (wsc *wsConnection) writeRoutine() {
defer wsc.baseConn.Close() defer wsc.baseConn.Close()
var n, err = int(0), error(nil)
for { for {
select { select {
case <-wsc.Quit: case <-wsc.Quit:
@ -446,14 +447,12 @@ func (wsc *wsConnection) writeRoutine() {
return return
} }
case msg := <-wsc.writeChan: case msg := <-wsc.writeChan:
buf := new(bytes.Buffer)
wire.WriteJSON(msg, buf, &n, &err)
jsonBytes, err := json.Marshal(msg)
if err != nil { if err != nil {
log.Error("Failed to marshal RPCResponse to JSON", "error", err) log.Error("Failed to marshal RPCResponse to JSON", "error", err)
} else { } else {
wsc.baseConn.SetWriteDeadline(time.Now().Add(time.Second * wsWriteTimeoutSeconds)) wsc.baseConn.SetWriteDeadline(time.Now().Add(time.Second * wsWriteTimeoutSeconds))
bufBytes := buf.Bytes()
if err = wsc.baseConn.WriteMessage(websocket.TextMessage, bufBytes); err != nil {
if err = wsc.baseConn.WriteMessage(websocket.TextMessage, jsonBytes); err != nil {
log.Warn("Failed to write response on websocket", "error", err) log.Warn("Failed to write response on websocket", "error", err)
wsc.Stop() wsc.Stop()
return return
@ -507,13 +506,18 @@ func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Requ
// rpc.websocket // rpc.websocket
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// returns is result struct and error. If error is not nil, return it
// NOTE: assume returns is result struct and error. If error is not nil, return it
func unreflectResult(returns []reflect.Value) (interface{}, error) { func unreflectResult(returns []reflect.Value) (interface{}, error) {
errV := returns[1] errV := returns[1]
if errV.Interface() != nil { if errV.Interface() != nil {
return nil, fmt.Errorf("%v", errV.Interface()) return nil, fmt.Errorf("%v", errV.Interface())
} }
return returns[0].Interface(), nil
rv := returns[0]
// the result is a registered interface,
// we need a pointer to it so we can marshal with type byte
rvp := reflect.New(rv.Type())
rvp.Elem().Set(rv)
return rvp.Interface(), nil
} }
// writes a list of available rpc endpoints as an html page // writes a list of available rpc endpoints as an html page


+ 7
- 2
server/http_server.go View File

@ -3,6 +3,7 @@ package rpcserver
import ( import (
"bufio" "bufio"
"encoding/json"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@ -12,7 +13,7 @@ import (
"github.com/tendermint/go-alert" "github.com/tendermint/go-alert"
. "github.com/tendermint/go-common" . "github.com/tendermint/go-common"
. "github.com/tendermint/go-rpc/types" . "github.com/tendermint/go-rpc/types"
"github.com/tendermint/go-wire"
//"github.com/tendermint/go-wire"
) )
func StartHTTPServer(listenAddr string, handler http.Handler) (net.Listener, error) { func StartHTTPServer(listenAddr string, handler http.Handler) (net.Listener, error) {
@ -32,7 +33,11 @@ func StartHTTPServer(listenAddr string, handler http.Handler) (net.Listener, err
} }
func WriteRPCResponseHTTP(w http.ResponseWriter, res RPCResponse) { func WriteRPCResponseHTTP(w http.ResponseWriter, res RPCResponse) {
jsonBytes := wire.JSONBytesPretty(res)
// jsonBytes := wire.JSONBytesPretty(res)
jsonBytes, err := json.Marshal(res)
if err != nil {
panic(err)
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200) w.WriteHeader(200)
w.Write(jsonBytes) w.Write(jsonBytes)


+ 10
- 6
types/types.go View File

@ -1,7 +1,10 @@
package rpctypes package rpctypes
import ( import (
"encoding/json"
"github.com/tendermint/go-events" "github.com/tendermint/go-events"
"github.com/tendermint/go-wire"
) )
type RPCRequest struct { type RPCRequest struct {
@ -39,17 +42,18 @@ type Result interface {
//---------------------------------------- //----------------------------------------
type RPCResponse struct { type RPCResponse struct {
JSONRPC string `json:"jsonrpc"`
ID string `json:"id"`
Result Result `json:"result"`
Error string `json:"error"`
JSONRPC string `json:"jsonrpc"`
ID string `json:"id"`
Result *json.RawMessage `json:"result"`
Error string `json:"error"`
} }
func NewRPCResponse(id string, res Result, err string) RPCResponse {
func NewRPCResponse(id string, res interface{}, err string) RPCResponse {
raw := json.RawMessage(wire.JSONBytes(res))
return RPCResponse{ return RPCResponse{
JSONRPC: "2.0", JSONRPC: "2.0",
ID: id, ID: id,
Result: res,
Result: &raw,
Error: err, Error: err,
} }
} }


Loading…
Cancel
Save