github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/tm/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  type Option func(*RPCFunc)
    27  
    28  // Cacheable enables returning a cache control header from RPC functions to
    29  // which it is applied.
    30  //
    31  // `noCacheDefArgs` is a list of argument names that, if omitted or set to
    32  // their defaults when calling the RPC function, will skip the response
    33  // caching.
    34  func Cacheable(noCacheDefArgs ...string) Option {
    35  	return func(r *RPCFunc) {
    36  		r.cacheable = true
    37  		r.noCacheDefArgs = make(map[string]interface{})
    38  		for _, arg := range noCacheDefArgs {
    39  			r.noCacheDefArgs[arg] = nil
    40  		}
    41  	}
    42  }
    43  
    44  // Ws enables WebSocket communication.
    45  func Ws() Option {
    46  	return func(r *RPCFunc) {
    47  		r.ws = true
    48  	}
    49  }
    50  
    51  // RPCFunc contains the introspected type information for a function
    52  type RPCFunc struct {
    53  	f              reflect.Value          // underlying rpc function
    54  	args           []reflect.Type         // type of each function arg
    55  	returns        []reflect.Type         // type of each return arg
    56  	argNames       []string               // name of each argument
    57  	cacheable      bool                   // enable cache control
    58  	ws             bool                   // enable websocket communication
    59  	noCacheDefArgs map[string]interface{} // a lookup table of args that, if not supplied or are set to default values, cause us to not cache
    60  }
    61  
    62  // NewRPCFunc wraps a function for introspection.
    63  // f is the function, args are comma separated argument names
    64  func NewRPCFunc(f interface{}, args string, options ...Option) *RPCFunc {
    65  	return newRPCFunc(f, args, options...)
    66  }
    67  
    68  // NewWSRPCFunc wraps a function for introspection and use in the websockets.
    69  func NewWSRPCFunc(f interface{}, args string, options ...Option) *RPCFunc {
    70  	options = append(options, Ws())
    71  	return newRPCFunc(f, args, options...)
    72  }
    73  
    74  // cacheableWithArgs returns whether or not a call to this function is cacheable,
    75  // given the specified arguments.
    76  func (f *RPCFunc) cacheableWithArgs(args []reflect.Value) bool {
    77  	if !f.cacheable {
    78  		return false
    79  	}
    80  	// Skip the context variable common to all RPC functions
    81  	for i := 1; i < len(f.args); i++ {
    82  		// f.argNames does not include the context variable
    83  		argName := f.argNames[i-1]
    84  		if _, hasDefault := f.noCacheDefArgs[argName]; hasDefault {
    85  			// Argument with default value was not supplied
    86  			if i >= len(args) {
    87  				return false
    88  			}
    89  			// Argument with default value is set to its zero value
    90  			if args[i].IsZero() {
    91  				return false
    92  			}
    93  		}
    94  	}
    95  	return true
    96  }
    97  
    98  func newRPCFunc(f interface{}, args string, options ...Option) *RPCFunc {
    99  	var argNames []string
   100  	if args != "" {
   101  		argNames = strings.Split(args, ",")
   102  	}
   103  
   104  	r := &RPCFunc{
   105  		f:        reflect.ValueOf(f),
   106  		args:     funcArgTypes(f),
   107  		returns:  funcReturnTypes(f),
   108  		argNames: argNames,
   109  	}
   110  
   111  	for _, opt := range options {
   112  		opt(r)
   113  	}
   114  
   115  	return r
   116  }
   117  
   118  // return a function's argument types
   119  func funcArgTypes(f interface{}) []reflect.Type {
   120  	t := reflect.TypeOf(f)
   121  	n := t.NumIn()
   122  	typez := make([]reflect.Type, n)
   123  	for i := 0; i < n; i++ {
   124  		typez[i] = t.In(i)
   125  	}
   126  	return typez
   127  }
   128  
   129  // return a function's return types
   130  func funcReturnTypes(f interface{}) []reflect.Type {
   131  	t := reflect.TypeOf(f)
   132  	n := t.NumOut()
   133  	typez := make([]reflect.Type, n)
   134  	for i := 0; i < n; i++ {
   135  		typez[i] = t.Out(i)
   136  	}
   137  	return typez
   138  }
   139  
   140  //-------------------------------------------------------------
   141  
   142  // NOTE: assume returns is result struct and error. If error is not nil, return it
   143  func unreflectResult(returns []reflect.Value) (interface{}, error) {
   144  	errV := returns[1]
   145  	if errV.Interface() != nil {
   146  		return nil, fmt.Errorf("%v", errV.Interface())
   147  	}
   148  	rv := returns[0]
   149  	// the result is a registered interface,
   150  	// we need a pointer to it so we can marshal with type byte
   151  	rvp := reflect.New(rv.Type())
   152  	rvp.Elem().Set(rv)
   153  	return rvp.Interface(), nil
   154  }