diff options
Diffstat (limited to 'rpc/utils.go')
-rw-r--r-- | rpc/utils.go | 226 |
1 files changed, 0 insertions, 226 deletions
diff --git a/rpc/utils.go b/rpc/utils.go deleted file mode 100644 index 7f7ac4520..000000000 --- a/rpc/utils.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package rpc - -import ( - "bufio" - "context" - crand "crypto/rand" - "encoding/binary" - "encoding/hex" - "math/rand" - "reflect" - "strings" - "sync" - "time" - "unicode" - "unicode/utf8" -) - -var ( - subscriptionIDGenMu sync.Mutex - subscriptionIDGen = idGenerator() -) - -// Is this an exported - upper case - name? -func isExported(name string) bool { - rune, _ := utf8.DecodeRuneInString(name) - return unicode.IsUpper(rune) -} - -// Is this type exported or a builtin? -func isExportedOrBuiltinType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - // PkgPath will be non-empty even for an exported type, - // so we need to check the type name as well. - return isExported(t.Name()) || t.PkgPath() == "" -} - -var contextType = reflect.TypeOf((*context.Context)(nil)).Elem() - -// isContextType returns an indication if the given t is of context.Context or *context.Context type -func isContextType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t == contextType -} - -var errorType = reflect.TypeOf((*error)(nil)).Elem() - -// Implements this type the error interface -func isErrorType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t.Implements(errorType) -} - -var subscriptionType = reflect.TypeOf((*Subscription)(nil)).Elem() - -// isSubscriptionType returns an indication if the given t is of Subscription or *Subscription type -func isSubscriptionType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - return t == subscriptionType -} - -// isPubSub tests whether the given method has as as first argument a context.Context -// and returns the pair (Subscription, error) -func isPubSub(methodType reflect.Type) bool { - // numIn(0) is the receiver type - if methodType.NumIn() < 2 || methodType.NumOut() != 2 { - return false - } - - return isContextType(methodType.In(1)) && - isSubscriptionType(methodType.Out(0)) && - isErrorType(methodType.Out(1)) -} - -// formatName will convert to first character to lower case -func formatName(name string) string { - ret := []rune(name) - if len(ret) > 0 { - ret[0] = unicode.ToLower(ret[0]) - } - return string(ret) -} - -// suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria -// for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server -// documentation for a summary of these criteria. -func suitableCallbacks(rcvr reflect.Value, typ reflect.Type) (callbacks, subscriptions) { - callbacks := make(callbacks) - subscriptions := make(subscriptions) - -METHODS: - for m := 0; m < typ.NumMethod(); m++ { - method := typ.Method(m) - mtype := method.Type - mname := formatName(method.Name) - if method.PkgPath != "" { // method must be exported - continue - } - - var h callback - h.isSubscribe = isPubSub(mtype) - h.rcvr = rcvr - h.method = method - h.errPos = -1 - - firstArg := 1 - numIn := mtype.NumIn() - if numIn >= 2 && mtype.In(1) == contextType { - h.hasCtx = true - firstArg = 2 - } - - if h.isSubscribe { - h.argTypes = make([]reflect.Type, numIn-firstArg) // skip rcvr type - for i := firstArg; i < numIn; i++ { - argType := mtype.In(i) - if isExportedOrBuiltinType(argType) { - h.argTypes[i-firstArg] = argType - } else { - continue METHODS - } - } - - subscriptions[mname] = &h - continue METHODS - } - - // determine method arguments, ignore first arg since it's the receiver type - // Arguments must be exported or builtin types - h.argTypes = make([]reflect.Type, numIn-firstArg) - for i := firstArg; i < numIn; i++ { - argType := mtype.In(i) - if !isExportedOrBuiltinType(argType) { - continue METHODS - } - h.argTypes[i-firstArg] = argType - } - - // check that all returned values are exported or builtin types - for i := 0; i < mtype.NumOut(); i++ { - if !isExportedOrBuiltinType(mtype.Out(i)) { - continue METHODS - } - } - - // when a method returns an error it must be the last returned value - h.errPos = -1 - for i := 0; i < mtype.NumOut(); i++ { - if isErrorType(mtype.Out(i)) { - h.errPos = i - break - } - } - - if h.errPos >= 0 && h.errPos != mtype.NumOut()-1 { - continue METHODS - } - - switch mtype.NumOut() { - case 0, 1, 2: - if mtype.NumOut() == 2 && h.errPos == -1 { // method must one return value and 1 error - continue METHODS - } - callbacks[mname] = &h - } - } - - return callbacks, subscriptions -} - -// idGenerator helper utility that generates a (pseudo) random sequence of -// bytes that are used to generate identifiers. -func idGenerator() *rand.Rand { - if seed, err := binary.ReadVarint(bufio.NewReader(crand.Reader)); err == nil { - return rand.New(rand.NewSource(seed)) - } - return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) -} - -// NewID generates a identifier that can be used as an identifier in the RPC interface. -// e.g. filter and subscription identifier. -func NewID() ID { - subscriptionIDGenMu.Lock() - defer subscriptionIDGenMu.Unlock() - - id := make([]byte, 16) - for i := 0; i < len(id); i += 7 { - val := subscriptionIDGen.Int63() - for j := 0; i+j < len(id) && j < 7; j++ { - id[i+j] = byte(val) - val >>= 8 - } - } - - rpcId := hex.EncodeToString(id) - // rpc ID's are RPC quantities, no leading zero's and 0 is 0x0 - rpcId = strings.TrimLeft(rpcId, "0") - if rpcId == "" { - rpcId = "0" - } - - return ID("0x" + rpcId) -} |