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 }