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