github.com/Oyster-zx/tendermint@v0.34.24-fork/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 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 }