github.com/okex/exchain@v1.8.0/libs/tendermint/rpc/jsonrpc/server/rpc_func.go (about)

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