github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/rpc/utils.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:42</date>
    10  //</624450109970583552>
    11  
    12  
    13  package rpc
    14  
    15  import (
    16  	"bufio"
    17  	"context"
    18  	crand "crypto/rand"
    19  	"encoding/binary"
    20  	"encoding/hex"
    21  	"math/rand"
    22  	"reflect"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  	"unicode"
    27  	"unicode/utf8"
    28  )
    29  
    30  var (
    31  	subscriptionIDGenMu sync.Mutex
    32  	subscriptionIDGen   = idGenerator()
    33  )
    34  
    35  //这是导出的大写名称吗?
    36  func isExported(name string) bool {
    37  	rune, _ := utf8.DecodeRuneInString(name)
    38  	return unicode.IsUpper(rune)
    39  }
    40  
    41  //此类型是导出的还是内置的?
    42  func isExportedOrBuiltinType(t reflect.Type) bool {
    43  	for t.Kind() == reflect.Ptr {
    44  		t = t.Elem()
    45  	}
    46  //pkgpath将不为空,即使对于导出的类型,
    47  //所以我们也需要检查类型名。
    48  	return isExported(t.Name()) || t.PkgPath() == ""
    49  }
    50  
    51  var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
    52  
    53  //isContextType返回一个指示,如果给定的t是context.context或*context.context类型
    54  func isContextType(t reflect.Type) bool {
    55  	for t.Kind() == reflect.Ptr {
    56  		t = t.Elem()
    57  	}
    58  	return t == contextType
    59  }
    60  
    61  var errorType = reflect.TypeOf((*error)(nil)).Elem()
    62  
    63  //实现此类型错误接口
    64  func isErrorType(t reflect.Type) bool {
    65  	for t.Kind() == reflect.Ptr {
    66  		t = t.Elem()
    67  	}
    68  	return t.Implements(errorType)
    69  }
    70  
    71  var subscriptionType = reflect.TypeOf((*Subscription)(nil)).Elem()
    72  
    73  //IssubscriptionType返回一个指示,如果给定的T是订阅类型或*订阅类型
    74  func isSubscriptionType(t reflect.Type) bool {
    75  	for t.Kind() == reflect.Ptr {
    76  		t = t.Elem()
    77  	}
    78  	return t == subscriptionType
    79  }
    80  
    81  //IsSubSub测试给定方法是否具有作为第一个参数的context.context
    82  //并返回对(订阅、错误)
    83  func isPubSub(methodType reflect.Type) bool {
    84  //numin(0)是接收器类型
    85  	if methodType.NumIn() < 2 || methodType.NumOut() != 2 {
    86  		return false
    87  	}
    88  
    89  	return isContextType(methodType.In(1)) &&
    90  		isSubscriptionType(methodType.Out(0)) &&
    91  		isErrorType(methodType.Out(1))
    92  }
    93  
    94  //formatname将转换为小写的第一个字符
    95  func formatName(name string) string {
    96  	ret := []rune(name)
    97  	if len(ret) > 0 {
    98  		ret[0] = unicode.ToLower(ret[0])
    99  	}
   100  	return string(ret)
   101  }
   102  
   103  //suitableCallbacks迭代给定类型的方法。它将确定一个方法是否满足标准
   104  //用于RPC回调或订阅回调,并将其添加到回调或订阅集合中。参见服务器
   105  //这些标准的总结文件。
   106  func suitableCallbacks(rcvr reflect.Value, typ reflect.Type) (callbacks, subscriptions) {
   107  	callbacks := make(callbacks)
   108  	subscriptions := make(subscriptions)
   109  
   110  METHODS:
   111  	for m := 0; m < typ.NumMethod(); m++ {
   112  		method := typ.Method(m)
   113  		mtype := method.Type
   114  		mname := formatName(method.Name)
   115  if method.PkgPath != "" { //必须导出方法
   116  			continue
   117  		}
   118  
   119  		var h callback
   120  		h.isSubscribe = isPubSub(mtype)
   121  		h.rcvr = rcvr
   122  		h.method = method
   123  		h.errPos = -1
   124  
   125  		firstArg := 1
   126  		numIn := mtype.NumIn()
   127  		if numIn >= 2 && mtype.In(1) == contextType {
   128  			h.hasCtx = true
   129  			firstArg = 2
   130  		}
   131  
   132  		if h.isSubscribe {
   133  h.argTypes = make([]reflect.Type, numIn-firstArg) //跳过RCVR型
   134  			for i := firstArg; i < numIn; i++ {
   135  				argType := mtype.In(i)
   136  				if isExportedOrBuiltinType(argType) {
   137  					h.argTypes[i-firstArg] = argType
   138  				} else {
   139  					continue METHODS
   140  				}
   141  			}
   142  
   143  			subscriptions[mname] = &h
   144  			continue METHODS
   145  		}
   146  
   147  //确定方法参数,忽略第一个参数,因为它是接收器类型
   148  //参数必须导出或内置类型
   149  		h.argTypes = make([]reflect.Type, numIn-firstArg)
   150  		for i := firstArg; i < numIn; i++ {
   151  			argType := mtype.In(i)
   152  			if !isExportedOrBuiltinType(argType) {
   153  				continue METHODS
   154  			}
   155  			h.argTypes[i-firstArg] = argType
   156  		}
   157  
   158  //检查所有返回值是否已导出或内置类型
   159  		for i := 0; i < mtype.NumOut(); i++ {
   160  			if !isExportedOrBuiltinType(mtype.Out(i)) {
   161  				continue METHODS
   162  			}
   163  		}
   164  
   165  //当方法返回错误时,它必须是最后返回的值
   166  		h.errPos = -1
   167  		for i := 0; i < mtype.NumOut(); i++ {
   168  			if isErrorType(mtype.Out(i)) {
   169  				h.errPos = i
   170  				break
   171  			}
   172  		}
   173  
   174  		if h.errPos >= 0 && h.errPos != mtype.NumOut()-1 {
   175  			continue METHODS
   176  		}
   177  
   178  		switch mtype.NumOut() {
   179  		case 0, 1, 2:
   180  if mtype.NumOut() == 2 && h.errPos == -1 { //方法必须有一个返回值和一个错误
   181  				continue METHODS
   182  			}
   183  			callbacks[mname] = &h
   184  		}
   185  	}
   186  
   187  	return callbacks, subscriptions
   188  }
   189  
   190  //生成(伪)随机序列
   191  //用于生成标识符的字节。
   192  func idGenerator() *rand.Rand {
   193  	if seed, err := binary.ReadVarint(bufio.NewReader(crand.Reader)); err == nil {
   194  		return rand.New(rand.NewSource(seed))
   195  	}
   196  	return rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
   197  }
   198  
   199  //newid生成一个标识符,可以在rpc接口中用作标识符。
   200  //例如,筛选和订阅标识符。
   201  func NewID() ID {
   202  	subscriptionIDGenMu.Lock()
   203  	defer subscriptionIDGenMu.Unlock()
   204  
   205  	id := make([]byte, 16)
   206  	for i := 0; i < len(id); i += 7 {
   207  		val := subscriptionIDGen.Int63()
   208  		for j := 0; i+j < len(id) && j < 7; j++ {
   209  			id[i+j] = byte(val)
   210  			val >>= 8
   211  		}
   212  	}
   213  
   214  	rpcId := hex.EncodeToString(id)
   215  //rpc id是rpc数量,没有前导零,0是0x0
   216  	rpcId = strings.TrimLeft(rpcId, "0")
   217  	if rpcId == "" {
   218  		rpcId = "0"
   219  	}
   220  
   221  	return ID("0x" + rpcId)
   222  }
   223