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  }