github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/rpc/jsonrpc/server/rpc_func.go (about)

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