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