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