github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/rpc/jsonrpc/server/rpc_func.go (about)

     1  package server
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"reflect"
     7  	"strings"
     8  
     9  	amino "github.com/tendermint/go-amino"
    10  
    11  	"github.com/franono/tendermint/libs/log"
    12  )
    13  
    14  // RegisterRPCFuncs adds a route for each function in the funcMap, as well as
    15  // general jsonrpc and websocket handlers for all functions. "result" is the
    16  // interface on which the result objects are registered, and is popualted with
    17  // every RPCResponse
    18  func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc, cdc *amino.Codec, logger log.Logger) {
    19  	// HTTP endpoints
    20  	for funcName, rpcFunc := range funcMap {
    21  		mux.HandleFunc("/"+funcName, makeHTTPHandler(rpcFunc, cdc, logger))
    22  	}
    23  
    24  	// JSONRPC endpoints
    25  	mux.HandleFunc("/", handleInvalidJSONRPCPaths(makeJSONRPCHandler(funcMap, cdc, logger)))
    26  }
    27  
    28  ///////////////////////////////////////////////////////////////////////////////
    29  // Function introspection
    30  ///////////////////////////////////////////////////////////////////////////////
    31  
    32  // RPCFunc contains the introspected type information for a function
    33  type RPCFunc struct {
    34  	f        reflect.Value  // underlying rpc function
    35  	args     []reflect.Type // type of each function arg
    36  	returns  []reflect.Type // type of each return arg
    37  	argNames []string       // name of each argument
    38  	ws       bool           // websocket only
    39  }
    40  
    41  // NewRPCFunc wraps a function for introspection.
    42  // f is the function, args are comma separated argument names
    43  func NewRPCFunc(f interface{}, args string) *RPCFunc {
    44  	return newRPCFunc(f, args, false)
    45  }
    46  
    47  // NewWSRPCFunc wraps a function for introspection and use in the websockets.
    48  func NewWSRPCFunc(f interface{}, args string) *RPCFunc {
    49  	return newRPCFunc(f, args, true)
    50  }
    51  
    52  func newRPCFunc(f interface{}, args string, ws bool) *RPCFunc {
    53  	var argNames []string
    54  	if args != "" {
    55  		argNames = strings.Split(args, ",")
    56  	}
    57  	return &RPCFunc{
    58  		f:        reflect.ValueOf(f),
    59  		args:     funcArgTypes(f),
    60  		returns:  funcReturnTypes(f),
    61  		argNames: argNames,
    62  		ws:       ws,
    63  	}
    64  }
    65  
    66  // return a function's argument types
    67  func funcArgTypes(f interface{}) []reflect.Type {
    68  	t := reflect.TypeOf(f)
    69  	n := t.NumIn()
    70  	typez := make([]reflect.Type, n)
    71  	for i := 0; i < n; i++ {
    72  		typez[i] = t.In(i)
    73  	}
    74  	return typez
    75  }
    76  
    77  // return a function's return types
    78  func funcReturnTypes(f interface{}) []reflect.Type {
    79  	t := reflect.TypeOf(f)
    80  	n := t.NumOut()
    81  	typez := make([]reflect.Type, n)
    82  	for i := 0; i < n; i++ {
    83  		typez[i] = t.Out(i)
    84  	}
    85  	return typez
    86  }
    87  
    88  //-------------------------------------------------------------
    89  
    90  // NOTE: assume returns is result struct and error. If error is not nil, return it
    91  func unreflectResult(returns []reflect.Value) (interface{}, error) {
    92  	errV := returns[1]
    93  	if errV.Interface() != nil {
    94  		return nil, fmt.Errorf("%v", errV.Interface())
    95  	}
    96  	rv := returns[0]
    97  	// the result is a registered interface,
    98  	// we need a pointer to it so we can marshal with type byte
    99  	rvp := reflect.New(rv.Type())
   100  	rvp.Elem().Set(rv)
   101  	return rvp.Interface(), nil
   102  }