github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/rpc/utils.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package rpc
    26  
    27  import (
    28  	"bufio"
    29  	"context"
    30  	crand "crypto/rand"
    31  	"encoding/binary"
    32  	"encoding/hex"
    33  	"math/rand"
    34  	"reflect"
    35  	"strings"
    36  	"sync"
    37  	"time"
    38  	"unicode"
    39  	"unicode/utf8"
    40  )
    41  
    42  var (
    43  	subscriptionIDGenMu sync.Mutex
    44  	subscriptionIDGen   = idGenerator()
    45  )
    46  
    47  //这是导出的大写名称吗?
    48  func isExported(name string) bool {
    49  	rune, _ := utf8.DecodeRuneInString(name)
    50  	return unicode.IsUpper(rune)
    51  }
    52  
    53  //此类型是导出的还是内置的?
    54  func isExportedOrBuiltinType(t reflect.Type) bool {
    55  	for t.Kind() == reflect.Ptr {
    56  		t = t.Elem()
    57  	}
    58  //pkgpath将不为空,即使对于导出的类型,
    59  //所以我们也需要检查类型名。
    60  	return isExported(t.Name()) || t.PkgPath() == ""
    61  }
    62  
    63  var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
    64  
    65  //isContextType返回一个指示,如果给定的t是context.context或*context.context类型
    66  func isContextType(t reflect.Type) bool {
    67  	for t.Kind() == reflect.Ptr {
    68  		t = t.Elem()
    69  	}
    70  	return t == contextType
    71  }
    72  
    73  var errorType = reflect.TypeOf((*error)(nil)).Elem()
    74  
    75  //实现此类型错误接口
    76  func isErrorType(t reflect.Type) bool {
    77  	for t.Kind() == reflect.Ptr {
    78  		t = t.Elem()
    79  	}
    80  	return t.Implements(errorType)
    81  }
    82  
    83  var subscriptionType = reflect.TypeOf((*Subscription)(nil)).Elem()
    84  
    85  //IssubscriptionType返回一个指示,如果给定的T是订阅类型或*订阅类型
    86  func isSubscriptionType(t reflect.Type) bool {
    87  	for t.Kind() == reflect.Ptr {
    88  		t = t.Elem()
    89  	}
    90  	return t == subscriptionType
    91  }
    92  
    93  //IsSubSub测试给定方法是否具有作为第一个参数的context.context
    94  //并返回对(订阅、错误)
    95  func isPubSub(methodType reflect.Type) bool {
    96  //numin(0)是接收器类型
    97  	if methodType.NumIn() < 2 || methodType.NumOut() != 2 {
    98  		return false
    99  	}
   100  
   101  	return isContextType(methodType.In(1)) &&
   102  		isSubscriptionType(methodType.Out(0)) &&
   103  		isErrorType(methodType.Out(1))
   104  }
   105  
   106  //formatname将转换为小写的第一个字符
   107  func formatName(name string) string {
   108  	ret := []rune(name)
   109  	if len(ret) > 0 {
   110  		ret[0] = unicode.ToLower(ret[0])
   111  	}
   112  	return string(ret)
   113  }
   114  
   115  //suitableCallbacks迭代给定类型的方法。它将确定一个方法是否满足标准
   116  //用于RPC回调或订阅回调,并将其添加到回调或订阅集合中。参见服务器
   117  //这些标准的总结文件。
   118  func suitableCallbacks(rcvr reflect.Value, typ reflect.Type) (callbacks, subscriptions) {
   119  	callbacks := make(callbacks)
   120  	subscriptions := make(subscriptions)
   121  
   122  METHODS:
   123  	for m := 0; m < typ.NumMethod(); m++ {
   124  		method := typ.Method(m)
   125  		mtype := method.Type
   126  		mname := formatName(method.Name)
   127  if method.PkgPath != "" { //必须导出方法
   128  			continue
   129  		}
   130  
   131  		var h callback
   132  		h.isSubscribe = isPubSub(mtype)
   133  		h.rcvr = rcvr
   134  		h.method = method
   135  		h.errPos = -1
   136  
   137  		firstArg := 1
   138  		numIn := mtype.NumIn()
   139  		if numIn >= 2 && mtype.In(1) == contextType {
   140  			h.hasCtx = true
   141  			firstArg = 2
   142  		}
   143  
   144  		if h.isSubscribe {
   145  h.argTypes = make([]reflect.Type, numIn-firstArg) //跳过RCVR型
   146  			for i := firstArg; i < numIn; i++ {
   147  				argType := mtype.In(i)
   148  				if isExportedOrBuiltinType(argType) {
   149  					h.argTypes[i-firstArg] = argType
   150  				} else {
   151  					continue METHODS
   152  				}
   153  			}
   154  
   155  			subscriptions[mname] = &h
   156  			continue METHODS
   157  		}
   158  
   159  //确定方法参数,忽略第一个参数,因为它是接收器类型
   160  //参数必须导出或内置类型
   161  		h.argTypes = make([]reflect.Type, numIn-firstArg)
   162  		for i := firstArg; i < numIn; i++ {
   163  			argType := mtype.In(i)
   164  			if !isExportedOrBuiltinType(argType) {
   165  				continue METHODS
   166  			}
   167  			h.argTypes[i-firstArg] = argType
   168  		}
   169  
   170  //检查所有返回值是否已导出或内置类型
   171  		for i := 0; i < mtype.NumOut(); i++ {
   172  			if !isExportedOrBuiltinType(mtype.Out(i)) {
   173  				continue METHODS
   174  			}
   175  		}
   176  
   177  //当方法返回错误时,它必须是最后返回的值
   178  		h.errPos = -1
   179  		for i := 0; i < mtype.NumOut(); i++ {
   180  			if isErrorType(mtype.Out(i)) {
   181  				h.errPos = i
   182  				break
   183  			}
   184  		}
   185  
   186  		if h.errPos >= 0 && h.errPos != mtype.NumOut()-1 {
   187  			continue METHODS
   188  		}
   189  
   190  		switch mtype.NumOut() {
   191  		case 0, 1, 2:
   192  if mtype.NumOut() == 2 && h.errPos == -1 { //方法必须有一个返回值和一个错误
   193  				continue METHODS
   194  			}
   195  			callbacks[mname] = &h
   196  		}
   197  	}
   198  
   199  	return callbacks, subscriptions
   200  }
   201  
   202  //生成(伪)随机序列
   203  //用于生成标识符的字节。
   204  func idGenerator() *rand.Rand {
   205  	if seed, err := binary.ReadVarint(bufio.NewReader(crand.Reader)); err == nil {
   206  		return rand.New(rand.NewSource(seed))
   207  	}
   208  	return rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
   209  }
   210  
   211  //newid生成一个标识符,可以在rpc接口中用作标识符。
   212  //例如,筛选和订阅标识符。
   213  func NewID() ID {
   214  	subscriptionIDGenMu.Lock()
   215  	defer subscriptionIDGenMu.Unlock()
   216  
   217  	id := make([]byte, 16)
   218  	for i := 0; i < len(id); i += 7 {
   219  		val := subscriptionIDGen.Int63()
   220  		for j := 0; i+j < len(id) && j < 7; j++ {
   221  			id[i+j] = byte(val)
   222  			val >>= 8
   223  		}
   224  	}
   225  
   226  	rpcId := hex.EncodeToString(id)
   227  //rpc id是rpc数量,没有前导零,0是0x0
   228  	rpcId = strings.TrimLeft(rpcId, "0")
   229  	if rpcId == "" {
   230  		rpcId = "0"
   231  	}
   232  
   233  	return ID("0x" + rpcId)
   234  }