github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/rpc/server.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 "context" 29 "fmt" 30 "reflect" 31 "runtime" 32 "strings" 33 "sync" 34 "sync/atomic" 35 36 mapset "github.com/deckarep/golang-set" 37 "github.com/ethereum/go-ethereum/log" 38 ) 39 40 const MetadataApi = "rpc" 41 42 //codecopy指定此codec支持哪种类型的消息 43 type CodecOption int 44 45 const ( 46 //OptionMethodInvocation表示编解码器支持RPC方法调用 47 OptionMethodInvocation CodecOption = 1 << iota 48 49 //选项订阅表示编解码器支持RPC通知 50 OptionSubscriptions = 1 << iota //支持酒吧子 51 ) 52 53 //NewServer将创建一个没有注册处理程序的新服务器实例。 54 func NewServer() *Server { 55 server := &Server{ 56 services: make(serviceRegistry), 57 codecs: mapset.NewSet(), 58 run: 1, 59 } 60 61 //注册一个默认服务,该服务将提供有关RPC服务的元信息,如服务和 62 //它提供的方法。 63 rpcService := &RPCService{server} 64 server.RegisterName(MetadataApi, rpcService) 65 66 return server 67 } 68 69 //rpcservice提供有关服务器的元信息。 70 //例如,提供有关加载模块的信息。 71 type RPCService struct { 72 server *Server 73 } 74 75 //模块返回带有版本号的RPC服务列表 76 func (s *RPCService) Modules() map[string]string { 77 modules := make(map[string]string) 78 for name := range s.server.services { 79 modules[name] = "1.0" 80 } 81 return modules 82 } 83 84 //registername将在给定名称下为给定的rcvr类型创建服务。当给定的RCVR上没有方法时 85 //匹配条件以成为RPC方法或订阅,将返回错误。否则,新服务是 86 //已创建并添加到此服务器实例服务的服务集合中。 87 func (s *Server) RegisterName(name string, rcvr interface{}) error { 88 if s.services == nil { 89 s.services = make(serviceRegistry) 90 } 91 92 svc := new(service) 93 svc.typ = reflect.TypeOf(rcvr) 94 rcvrVal := reflect.ValueOf(rcvr) 95 96 if name == "" { 97 return fmt.Errorf("no service name for type %s", svc.typ.String()) 98 } 99 if !isExported(reflect.Indirect(rcvrVal).Type().Name()) { 100 return fmt.Errorf("%s is not exported", reflect.Indirect(rcvrVal).Type().Name()) 101 } 102 103 methods, subscriptions := suitableCallbacks(rcvrVal, svc.typ) 104 105 if len(methods) == 0 && len(subscriptions) == 0 { 106 return fmt.Errorf("Service %T doesn't have any suitable methods/subscriptions to expose", rcvr) 107 } 108 109 //已在给定名称下注册了以前的服务,合并方法/订阅 110 if regsvc, present := s.services[name]; present { 111 for _, m := range methods { 112 regsvc.callbacks[formatName(m.method.Name)] = m 113 } 114 for _, s := range subscriptions { 115 regsvc.subscriptions[formatName(s.method.Name)] = s 116 } 117 return nil 118 } 119 120 svc.name = name 121 svc.callbacks, svc.subscriptions = methods, subscriptions 122 123 s.services[svc.name] = svc 124 return nil 125 } 126 127 //ServerRequest将从编解码器读取请求,调用RPC回调和 128 //将响应写入给定的编解码器。 129 // 130 //如果singleshot为true,它将处理单个请求,否则它将处理 131 //直到编解码器在读取请求时返回错误为止的请求(在大多数情况下 132 //EOF)。当singleshot为false时,它并行执行请求。 133 func (s *Server) serveRequest(ctx context.Context, codec ServerCodec, singleShot bool, options CodecOption) error { 134 var pend sync.WaitGroup 135 136 defer func() { 137 if err := recover(); err != nil { 138 const size = 64 << 10 139 buf := make([]byte, size) 140 buf = buf[:runtime.Stack(buf, false)] 141 log.Error(string(buf)) 142 } 143 s.codecsMu.Lock() 144 s.codecs.Remove(codec) 145 s.codecsMu.Unlock() 146 }() 147 148 //ctx,取消:=context.withcancel(context.background()) 149 ctx, cancel := context.WithCancel(ctx) 150 defer cancel() 151 152 //如果编解码器支持通知,则包含回调可以使用的通知程序 153 //向客户端发送通知。它绑定到编解码器/连接。如果 154 //连接已关闭通知程序将停止并取消所有活动订阅。 155 if options&OptionSubscriptions == OptionSubscriptions { 156 ctx = context.WithValue(ctx, notifierKey{}, newNotifier(codec)) 157 } 158 s.codecsMu.Lock() 159 if atomic.LoadInt32(&s.run) != 1 { //服务器停止 160 s.codecsMu.Unlock() 161 return &shutdownError{} 162 } 163 s.codecs.Add(codec) 164 s.codecsMu.Unlock() 165 166 //测试服务器是否被命令停止 167 for atomic.LoadInt32(&s.run) == 1 { 168 reqs, batch, err := s.readRequest(codec) 169 if err != nil { 170 //如果发生分析错误,则发送错误 171 if err.Error() != "EOF" { 172 log.Debug(fmt.Sprintf("read error %v\n", err)) 173 codec.Write(codec.CreateErrorResponse(nil, err)) 174 } 175 //错误或流结束,等待请求并关闭 176 pend.Wait() 177 return nil 178 } 179 180 //检查服务器是否被命令关闭并返回错误 181 //告诉客户他的请求失败了。 182 if atomic.LoadInt32(&s.run) != 1 { 183 err = &shutdownError{} 184 if batch { 185 resps := make([]interface{}, len(reqs)) 186 for i, r := range reqs { 187 resps[i] = codec.CreateErrorResponse(&r.id, err) 188 } 189 codec.Write(resps) 190 } else { 191 codec.Write(codec.CreateErrorResponse(&reqs[0].id, err)) 192 } 193 return nil 194 } 195 //如果正在执行单次放炮请求,请立即运行并返回 196 if singleShot { 197 if batch { 198 s.execBatch(ctx, codec, reqs) 199 } else { 200 s.exec(ctx, codec, reqs[0]) 201 } 202 return nil 203 } 204 //对于多发连接,启动Goroutine发球并回环 205 pend.Add(1) 206 207 go func(reqs []*serverRequest, batch bool) { 208 defer pend.Done() 209 if batch { 210 s.execBatch(ctx, codec, reqs) 211 } else { 212 s.exec(ctx, codec, reqs[0]) 213 } 214 }(reqs, batch) 215 } 216 return nil 217 } 218 219 //ServeDec从编解码器读取传入的请求,调用适当的回调并写入 220 //使用给定的编解码器返回响应。它将一直阻塞,直到关闭编解码器或服务器 221 //停止。无论哪种情况,编解码器都是关闭的。 222 func (s *Server) ServeCodec(codec ServerCodec, options CodecOption) { 223 defer codec.Close() 224 s.serveRequest(context.Background(), codec, false, options) 225 } 226 227 //ServeSingleRequest从给定的编解码器读取和处理单个RPC请求。它不会 228 //除非发生不可恢复的错误,否则请关闭编解码器。注意,此方法将在 229 //已处理单个请求! 230 func (s *Server) ServeSingleRequest(ctx context.Context, codec ServerCodec, options CodecOption) { 231 s.serveRequest(ctx, codec, true, options) 232 } 233 234 //stop将停止读取新请求,等待stoppendingrequestTimeout允许挂起的请求完成, 235 //关闭将取消挂起请求/订阅的所有编解码器。 236 func (s *Server) Stop() { 237 if atomic.CompareAndSwapInt32(&s.run, 1, 0) { 238 log.Debug("RPC Server shutdown initiatied") 239 s.codecsMu.Lock() 240 defer s.codecsMu.Unlock() 241 s.codecs.Each(func(c interface{}) bool { 242 c.(ServerCodec).Close() 243 return true 244 }) 245 } 246 } 247 248 //CreateSubscription将调用订阅回调并返回订阅ID或错误。 249 func (s *Server) createSubscription(ctx context.Context, c ServerCodec, req *serverRequest) (ID, error) { 250 //订阅的第一个参数是可选参数后面的上下文 251 args := []reflect.Value{req.callb.rcvr, reflect.ValueOf(ctx)} 252 args = append(args, req.args...) 253 reply := req.callb.method.Func.Call(args) 254 255 if !reply[1].IsNil() { //订阅创建失败 256 return "", reply[1].Interface().(error) 257 } 258 259 return reply[0].Interface().(*Subscription).ID, nil 260 } 261 262 //句柄执行请求并返回回调的响应。 263 func (s *Server) handle(ctx context.Context, codec ServerCodec, req *serverRequest) (interface{}, func()) { 264 if req.err != nil { 265 return codec.CreateErrorResponse(&req.id, req.err), nil 266 } 267 268 if req.isUnsubscribe { //取消订阅,第一个参数必须是订阅ID 269 if len(req.args) >= 1 && req.args[0].Kind() == reflect.String { 270 notifier, supported := NotifierFromContext(ctx) 271 if !supported { //接口不支持订阅(例如http) 272 return codec.CreateErrorResponse(&req.id, &callbackError{ErrNotificationsUnsupported.Error()}), nil 273 } 274 275 subid := ID(req.args[0].String()) 276 if err := notifier.unsubscribe(subid); err != nil { 277 return codec.CreateErrorResponse(&req.id, &callbackError{err.Error()}), nil 278 } 279 280 return codec.CreateResponse(req.id, true), nil 281 } 282 return codec.CreateErrorResponse(&req.id, &invalidParamsError{"Expected subscription id as first argument"}), nil 283 } 284 285 if req.callb.isSubscribe { 286 subid, err := s.createSubscription(ctx, codec, req) 287 if err != nil { 288 return codec.CreateErrorResponse(&req.id, &callbackError{err.Error()}), nil 289 } 290 291 //在子ID成功发送到客户端后激活订阅 292 activateSub := func() { 293 notifier, _ := NotifierFromContext(ctx) 294 notifier.activate(subid, req.svcname) 295 } 296 297 return codec.CreateResponse(req.id, subid), activateSub 298 } 299 300 //常规RPC调用,准备参数 301 if len(req.args) != len(req.callb.argTypes) { 302 rpcErr := &invalidParamsError{fmt.Sprintf("%s%s%s expects %d parameters, got %d", 303 req.svcname, serviceMethodSeparator, req.callb.method.Name, 304 len(req.callb.argTypes), len(req.args))} 305 return codec.CreateErrorResponse(&req.id, rpcErr), nil 306 } 307 308 arguments := []reflect.Value{req.callb.rcvr} 309 if req.callb.hasCtx { 310 arguments = append(arguments, reflect.ValueOf(ctx)) 311 } 312 if len(req.args) > 0 { 313 arguments = append(arguments, req.args...) 314 } 315 316 //执行rpc方法并返回结果 317 reply := req.callb.method.Func.Call(arguments) 318 if len(reply) == 0 { 319 return codec.CreateResponse(req.id, nil), nil 320 } 321 if req.callb.errPos >= 0 { //测试方法是否返回错误 322 if !reply[req.callb.errPos].IsNil() { 323 e := reply[req.callb.errPos].Interface().(error) 324 res := codec.CreateErrorResponse(&req.id, &callbackError{e.Error()}) 325 return res, nil 326 } 327 } 328 return codec.CreateResponse(req.id, reply[0].Interface()), nil 329 } 330 331 //exec执行给定的请求,并使用codec将结果写回。 332 func (s *Server) exec(ctx context.Context, codec ServerCodec, req *serverRequest) { 333 var response interface{} 334 var callback func() 335 if req.err != nil { 336 response = codec.CreateErrorResponse(&req.id, req.err) 337 } else { 338 response, callback = s.handle(ctx, codec, req) 339 } 340 341 if err := codec.Write(response); err != nil { 342 log.Error(fmt.Sprintf("%v\n", err)) 343 codec.Close() 344 } 345 346 //当请求是订阅请求时,允许激活这些订阅 347 if callback != nil { 348 callback() 349 } 350 } 351 352 //execbatch执行给定的请求,并使用codec将结果写回。 353 //它只会在处理最后一个请求时写回响应。 354 func (s *Server) execBatch(ctx context.Context, codec ServerCodec, requests []*serverRequest) { 355 responses := make([]interface{}, len(requests)) 356 var callbacks []func() 357 for i, req := range requests { 358 if req.err != nil { 359 responses[i] = codec.CreateErrorResponse(&req.id, req.err) 360 } else { 361 var callback func() 362 if responses[i], callback = s.handle(ctx, codec, req); callback != nil { 363 callbacks = append(callbacks, callback) 364 } 365 } 366 } 367 368 if err := codec.Write(responses); err != nil { 369 log.Error(fmt.Sprintf("%v\n", err)) 370 codec.Close() 371 } 372 373 //当请求持有多个订阅请求之一时,这将允许激活这些订阅 374 for _, c := range callbacks { 375 c() 376 } 377 } 378 379 //readrequest从编解码器请求下一个(批处理)请求。它会把收藏品送回 380 //请求数,指示请求是否为批处理、无效的请求标识符和 381 //无法读取/分析请求时出错。 382 func (s *Server) readRequest(codec ServerCodec) ([]*serverRequest, bool, Error) { 383 reqs, batch, err := codec.ReadRequestHeaders() 384 if err != nil { 385 return nil, batch, err 386 } 387 388 requests := make([]*serverRequest, len(reqs)) 389 390 //验证请求 391 for i, r := range reqs { 392 var ok bool 393 var svc *service 394 395 if r.err != nil { 396 requests[i] = &serverRequest{id: r.id, err: r.err} 397 continue 398 } 399 400 if r.isPubSub && strings.HasSuffix(r.method, unsubscribeMethodSuffix) { 401 requests[i] = &serverRequest{id: r.id, isUnsubscribe: true} 402 argTypes := []reflect.Type{reflect.TypeOf("")} //预期订阅ID为第一个参数 403 if args, err := codec.ParseRequestArguments(argTypes, r.params); err == nil { 404 requests[i].args = args 405 } else { 406 requests[i].err = &invalidParamsError{err.Error()} 407 } 408 continue 409 } 410 411 if svc, ok = s.services[r.service]; !ok { //RPC方法不可用 412 requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} 413 continue 414 } 415 416 if r.isPubSub { //eth-subscribe,r.method包含订阅方法名称 417 if callb, ok := svc.subscriptions[r.method]; ok { 418 requests[i] = &serverRequest{id: r.id, svcname: svc.name, callb: callb} 419 if r.params != nil && len(callb.argTypes) > 0 { 420 argTypes := []reflect.Type{reflect.TypeOf("")} 421 argTypes = append(argTypes, callb.argTypes...) 422 if args, err := codec.ParseRequestArguments(argTypes, r.params); err == nil { 423 requests[i].args = args[1:] //第一个是service.method name,它不是实际参数 424 } else { 425 requests[i].err = &invalidParamsError{err.Error()} 426 } 427 } 428 } else { 429 requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} 430 } 431 continue 432 } 433 434 if callb, ok := svc.callbacks[r.method]; ok { //查找RPC方法 435 requests[i] = &serverRequest{id: r.id, svcname: svc.name, callb: callb} 436 if r.params != nil && len(callb.argTypes) > 0 { 437 if args, err := codec.ParseRequestArguments(callb.argTypes, r.params); err == nil { 438 requests[i].args = args 439 } else { 440 requests[i].err = &invalidParamsError{err.Error()} 441 } 442 } 443 continue 444 } 445 446 requests[i] = &serverRequest{id: r.id, err: &methodNotFoundError{r.service, r.method}} 447 } 448 449 return requests, batch, nil 450 }