github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/rpc/client.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  //</624450108456439808>
    11  
    12  
    13  package rpc
    14  
    15  import (
    16  	"bytes"
    17  	"container/list"
    18  	"context"
    19  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  	"net"
    23  	"net/url"
    24  	"reflect"
    25  	"strconv"
    26  	"strings"
    27  	"sync"
    28  	"sync/atomic"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/log"
    32  )
    33  
    34  var (
    35  	ErrClientQuit                = errors.New("client is closed")
    36  	ErrNoResult                  = errors.New("no result in JSON-RPC response")
    37  	ErrSubscriptionQueueOverflow = errors.New("subscription queue overflow")
    38  )
    39  
    40  const (
    41  //超时
    42  	tcpKeepAliveInterval = 30 * time.Second
    43  defaultDialTimeout   = 10 * time.Second //如果上下文没有截止时间,则在拨号时使用
    44  defaultWriteTimeout  = 10 * time.Second //如果上下文没有截止时间,则用于调用
    45  subscribeTimeout     = 5 * time.Second  //总超时eth_subscribe,rpc_模块调用
    46  )
    47  
    48  const (
    49  //当订阅服务器无法跟上时,将删除订阅。
    50  //
    51  //这可以通过为通道提供足够大的缓冲区来解决,
    52  //但这在文件中可能不方便也很难解释。另一个问题是
    53  //缓冲通道是指即使不需要缓冲区,缓冲区也是静态的。
    54  //大部分时间。
    55  //
    56  //这里采用的方法是维护每个订阅的链表缓冲区
    57  //按需缩小。如果缓冲区达到以下大小,则订阅为
    58  //下降。
    59  	maxClientSubscriptionBuffer = 20000
    60  )
    61  
    62  //batchelem是批处理请求中的元素。
    63  type BatchElem struct {
    64  	Method string
    65  	Args   []interface{}
    66  //结果未显示在此字段中。结果必须设置为
    67  //所需类型的非零指针值,否则响应将为
    68  //丢弃的。
    69  	Result interface{}
    70  //如果服务器返回此请求的错误,或如果
    71  //解组为结果失败。未设置I/O错误。
    72  	Error error
    73  }
    74  
    75  //此类型的值可以是JSON-RPC请求、通知、成功响应或
    76  //错误响应。它是哪一个取决于田地。
    77  type jsonrpcMessage struct {
    78  	Version string          `json:"jsonrpc"`
    79  	ID      json.RawMessage `json:"id,omitempty"`
    80  	Method  string          `json:"method,omitempty"`
    81  	Params  json.RawMessage `json:"params,omitempty"`
    82  	Error   *jsonError      `json:"error,omitempty"`
    83  	Result  json.RawMessage `json:"result,omitempty"`
    84  }
    85  
    86  func (msg *jsonrpcMessage) isNotification() bool {
    87  	return msg.ID == nil && msg.Method != ""
    88  }
    89  
    90  func (msg *jsonrpcMessage) isResponse() bool {
    91  	return msg.hasValidID() && msg.Method == "" && len(msg.Params) == 0
    92  }
    93  
    94  func (msg *jsonrpcMessage) hasValidID() bool {
    95  	return len(msg.ID) > 0 && msg.ID[0] != '{' && msg.ID[0] != '['
    96  }
    97  
    98  func (msg *jsonrpcMessage) String() string {
    99  	b, _ := json.Marshal(msg)
   100  	return string(b)
   101  }
   102  
   103  //客户端表示到RPC服务器的连接。
   104  type Client struct {
   105  	idCounter   uint32
   106  	connectFunc func(ctx context.Context) (net.Conn, error)
   107  	isHTTP      bool
   108  
   109  //WRITECONN只能安全地访问外部调度,使用
   110  //写入锁定保持。通过发送
   111  //请求操作并通过发送发送完成释放。
   112  	writeConn net.Conn
   113  
   114  //派遣
   115  	close       chan struct{}
   116  closing     chan struct{}                  //客户端退出时关闭
   117  didClose    chan struct{}                  //客户端退出时关闭
   118  reconnected chan net.Conn                  //写入/重新连接发送新连接的位置
   119  readErr     chan error                     //读取错误
   120  readResp    chan []*jsonrpcMessage         //读取的有效消息
   121  requestOp   chan *requestOp                //用于注册响应ID
   122  sendDone    chan error                     //信号写入完成,释放写入锁定
   123  respWait    map[string]*requestOp          //主动请求
   124  subs        map[string]*ClientSubscription //活动订阅
   125  }
   126  
   127  type requestOp struct {
   128  	ids  []json.RawMessage
   129  	err  error
   130  resp chan *jsonrpcMessage //接收最多len(id)响应
   131  sub  *ClientSubscription  //仅为ethsubscribe请求设置
   132  }
   133  
   134  func (op *requestOp) wait(ctx context.Context) (*jsonrpcMessage, error) {
   135  	select {
   136  	case <-ctx.Done():
   137  		return nil, ctx.Err()
   138  	case resp := <-op.resp:
   139  		return resp, op.err
   140  	}
   141  }
   142  
   143  //拨号为给定的URL创建新的客户端。
   144  //
   145  //当前支持的URL方案有“http”、“https”、“ws”和“wss”。如果RAWURL是
   146  //没有URL方案的文件名,使用Unix建立本地套接字连接
   147  //支持的平台上的域套接字和Windows上的命名管道。如果你想
   148  //配置传输选项,使用dialHTTP、dialWebSocket或dialIPC。
   149  //
   150  //对于WebSocket连接,原点设置为本地主机名。
   151  //
   152  //如果连接丢失,客户端将自动重新连接。
   153  func Dial(rawurl string) (*Client, error) {
   154  	return DialContext(context.Background(), rawurl)
   155  }
   156  
   157  //DialContext创建一个新的RPC客户端,就像Dial一样。
   158  //
   159  //上下文用于取消或超时初始连接建立。它确实
   160  //不影响与客户的后续交互。
   161  func DialContext(ctx context.Context, rawurl string) (*Client, error) {
   162  	u, err := url.Parse(rawurl)
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	switch u.Scheme {
   167  	case "http", "https":
   168  		return DialHTTP(rawurl)
   169  	case "ws", "wss":
   170  		return DialWebsocket(ctx, rawurl, "")
   171  	case "stdio":
   172  		return DialStdIO(ctx)
   173  	case "":
   174  		return DialIPC(ctx, rawurl)
   175  	default:
   176  		return nil, fmt.Errorf("no known transport for URL scheme %q", u.Scheme)
   177  	}
   178  }
   179  
   180  func newClient(initctx context.Context, connectFunc func(context.Context) (net.Conn, error)) (*Client, error) {
   181  	conn, err := connectFunc(initctx)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	_, isHTTP := conn.(*httpConn)
   186  	c := &Client{
   187  		writeConn:   conn,
   188  		isHTTP:      isHTTP,
   189  		connectFunc: connectFunc,
   190  		close:       make(chan struct{}),
   191  		closing:     make(chan struct{}),
   192  		didClose:    make(chan struct{}),
   193  		reconnected: make(chan net.Conn),
   194  		readErr:     make(chan error),
   195  		readResp:    make(chan []*jsonrpcMessage),
   196  		requestOp:   make(chan *requestOp),
   197  		sendDone:    make(chan error, 1),
   198  		respWait:    make(map[string]*requestOp),
   199  		subs:        make(map[string]*ClientSubscription),
   200  	}
   201  	if !isHTTP {
   202  		go c.dispatch(conn)
   203  	}
   204  	return c, nil
   205  }
   206  
   207  func (c *Client) nextID() json.RawMessage {
   208  	id := atomic.AddUint32(&c.idCounter, 1)
   209  	return []byte(strconv.FormatUint(uint64(id), 10))
   210  }
   211  
   212  //supportedmodules调用rpc_modules方法,检索
   213  //服务器上可用的API。
   214  func (c *Client) SupportedModules() (map[string]string, error) {
   215  	var result map[string]string
   216  	ctx, cancel := context.WithTimeout(context.Background(), subscribeTimeout)
   217  	defer cancel()
   218  	err := c.CallContext(ctx, &result, "rpc_modules")
   219  	return result, err
   220  }
   221  
   222  //CLOSE关闭客户机,中止任何飞行中的请求。
   223  func (c *Client) Close() {
   224  	if c.isHTTP {
   225  		return
   226  	}
   227  	select {
   228  	case c.close <- struct{}{}:
   229  		<-c.didClose
   230  	case <-c.didClose:
   231  	}
   232  }
   233  
   234  //调用使用给定的参数执行JSON-RPC调用,并将其解组为
   235  //如果没有发生错误,则返回结果。
   236  //
   237  //结果必须是一个指针,以便包JSON可以解组到其中。你
   238  //也可以传递nil,在这种情况下,结果将被忽略。
   239  func (c *Client) Call(result interface{}, method string, args ...interface{}) error {
   240  	ctx := context.Background()
   241  	return c.CallContext(ctx, result, method, args...)
   242  }
   243  
   244  //callContext使用给定的参数执行JSON-RPC调用。如果上下文是
   245  //在成功返回调用之前取消,callContext立即返回。
   246  //
   247  //结果必须是一个指针,以便包JSON可以解组到其中。你
   248  //也可以传递nil,在这种情况下,结果将被忽略。
   249  func (c *Client) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
   250  	msg, err := c.newMessage(method, args...)
   251  	if err != nil {
   252  		return err
   253  	}
   254  	op := &requestOp{ids: []json.RawMessage{msg.ID}, resp: make(chan *jsonrpcMessage, 1)}
   255  
   256  	if c.isHTTP {
   257  		err = c.sendHTTP(ctx, op, msg)
   258  	} else {
   259  		err = c.send(ctx, op, msg)
   260  	}
   261  	if err != nil {
   262  		return err
   263  	}
   264  
   265  //调度已接受请求,并将在退出时关闭通道。
   266  	switch resp, err := op.wait(ctx); {
   267  	case err != nil:
   268  		return err
   269  	case resp.Error != nil:
   270  		return resp.Error
   271  	case len(resp.Result) == 0:
   272  		return ErrNoResult
   273  	default:
   274  		return json.Unmarshal(resp.Result, &result)
   275  	}
   276  }
   277  
   278  //批处理调用将所有给定的请求作为单个批处理发送,并等待服务器
   279  //为所有人返回响应。
   280  //
   281  //与调用不同,批调用只返回I/O错误。任何特定于的错误
   282  //通过相应批处理元素的错误字段报告请求。
   283  //
   284  //注意,批处理调用不能在服务器端以原子方式执行。
   285  func (c *Client) BatchCall(b []BatchElem) error {
   286  	ctx := context.Background()
   287  	return c.BatchCallContext(ctx, b)
   288  }
   289  
   290  //批处理调用将所有给定的请求作为单个批处理发送,并等待服务器
   291  //为所有人返回响应。等待持续时间由
   292  //上下文的最后期限。
   293  //
   294  //与callContext不同,batchcallContext只返回已发生的错误
   295  //发送请求时。任何特定于请求的错误都会通过
   296  //对应批处理元素的错误字段。
   297  //
   298  //注意,批处理调用不能在服务器端以原子方式执行。
   299  func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error {
   300  	msgs := make([]*jsonrpcMessage, len(b))
   301  	op := &requestOp{
   302  		ids:  make([]json.RawMessage, len(b)),
   303  		resp: make(chan *jsonrpcMessage, len(b)),
   304  	}
   305  	for i, elem := range b {
   306  		msg, err := c.newMessage(elem.Method, elem.Args...)
   307  		if err != nil {
   308  			return err
   309  		}
   310  		msgs[i] = msg
   311  		op.ids[i] = msg.ID
   312  	}
   313  
   314  	var err error
   315  	if c.isHTTP {
   316  		err = c.sendBatchHTTP(ctx, op, msgs)
   317  	} else {
   318  		err = c.send(ctx, op, msgs)
   319  	}
   320  
   321  //等待所有响应返回。
   322  	for n := 0; n < len(b) && err == nil; n++ {
   323  		var resp *jsonrpcMessage
   324  		resp, err = op.wait(ctx)
   325  		if err != nil {
   326  			break
   327  		}
   328  //找到与此响应对应的元素。
   329  //由于调度,元素被保证存在
   330  //只向我们的频道发送有效的ID。
   331  		var elem *BatchElem
   332  		for i := range msgs {
   333  			if bytes.Equal(msgs[i].ID, resp.ID) {
   334  				elem = &b[i]
   335  				break
   336  			}
   337  		}
   338  		if resp.Error != nil {
   339  			elem.Error = resp.Error
   340  			continue
   341  		}
   342  		if len(resp.Result) == 0 {
   343  			elem.Error = ErrNoResult
   344  			continue
   345  		}
   346  		elem.Error = json.Unmarshal(resp.Result, elem.Result)
   347  	}
   348  	return err
   349  }
   350  
   351  //ethsubscribe在“eth”名称空间下注册一个订阅。
   352  func (c *Client) EthSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) {
   353  	return c.Subscribe(ctx, "eth", channel, args...)
   354  }
   355  
   356  //shhsubscribe在“shh”名称空间下注册一个订阅。
   357  func (c *Client) ShhSubscribe(ctx context.Context, channel interface{}, args ...interface{}) (*ClientSubscription, error) {
   358  	return c.Subscribe(ctx, "shh", channel, args...)
   359  }
   360  
   361  //subscribe使用给定的参数调用“<namespace>\u subscribe”方法,
   362  //注册订阅。订阅的服务器通知为
   363  //发送到给定的频道。通道的元素类型必须与
   364  //订阅返回的内容类型应为。
   365  //
   366  //context参数取消设置订阅但没有的RPC请求
   367  //订阅返回后对订阅的影响。
   368  //
   369  //缓慢的订户最终将被删除。客户端缓冲区最多8000个通知
   370  //在考虑用户死亡之前。订阅错误通道将接收
   371  //errSubscriptionQueueOverflow。在通道上使用足够大的缓冲区或确保
   372  //通道通常至少有一个读卡器来防止这个问题。
   373  func (c *Client) Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (*ClientSubscription, error) {
   374  //首先检查通道类型。
   375  	chanVal := reflect.ValueOf(channel)
   376  	if chanVal.Kind() != reflect.Chan || chanVal.Type().ChanDir()&reflect.SendDir == 0 {
   377  		panic("first argument to Subscribe must be a writable channel")
   378  	}
   379  	if chanVal.IsNil() {
   380  		panic("channel given to Subscribe must not be nil")
   381  	}
   382  	if c.isHTTP {
   383  		return nil, ErrNotificationsUnsupported
   384  	}
   385  
   386  	msg, err := c.newMessage(namespace+subscribeMethodSuffix, args...)
   387  	if err != nil {
   388  		return nil, err
   389  	}
   390  	op := &requestOp{
   391  		ids:  []json.RawMessage{msg.ID},
   392  		resp: make(chan *jsonrpcMessage),
   393  		sub:  newClientSubscription(c, namespace, chanVal),
   394  	}
   395  
   396  //发送订阅请求。
   397  //响应的到达和有效性在Sub.Quit上发出信号。
   398  	if err := c.send(ctx, op, msg); err != nil {
   399  		return nil, err
   400  	}
   401  	if _, err := op.wait(ctx); err != nil {
   402  		return nil, err
   403  	}
   404  	return op.sub, nil
   405  }
   406  
   407  func (c *Client) newMessage(method string, paramsIn ...interface{}) (*jsonrpcMessage, error) {
   408  	params, err := json.Marshal(paramsIn)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	return &jsonrpcMessage{Version: "2.0", ID: c.nextID(), Method: method, Params: params}, nil
   413  }
   414  
   415  //发送寄存器op和调度循环,然后在连接上发送msg。
   416  //如果发送失败,则注销OP。
   417  func (c *Client) send(ctx context.Context, op *requestOp, msg interface{}) error {
   418  	select {
   419  	case c.requestOp <- op:
   420  		log.Trace("", "msg", log.Lazy{Fn: func() string {
   421  			return fmt.Sprint("sending ", msg)
   422  		}})
   423  		err := c.write(ctx, msg)
   424  		c.sendDone <- err
   425  		return err
   426  	case <-ctx.Done():
   427  //如果客户端过载或无法跟上,就会发生这种情况。
   428  //订阅通知。
   429  		return ctx.Err()
   430  	case <-c.closing:
   431  		return ErrClientQuit
   432  	case <-c.didClose:
   433  		return ErrClientQuit
   434  	}
   435  }
   436  
   437  func (c *Client) write(ctx context.Context, msg interface{}) error {
   438  	deadline, ok := ctx.Deadline()
   439  	if !ok {
   440  		deadline = time.Now().Add(defaultWriteTimeout)
   441  	}
   442  //上一次写入失败。尝试建立新连接。
   443  	if c.writeConn == nil {
   444  		if err := c.reconnect(ctx); err != nil {
   445  			return err
   446  		}
   447  	}
   448  	c.writeConn.SetWriteDeadline(deadline)
   449  	err := json.NewEncoder(c.writeConn).Encode(msg)
   450  	c.writeConn.SetWriteDeadline(time.Time{})
   451  	if err != nil {
   452  		c.writeConn = nil
   453  	}
   454  	return err
   455  }
   456  
   457  func (c *Client) reconnect(ctx context.Context) error {
   458  	newconn, err := c.connectFunc(ctx)
   459  	if err != nil {
   460  		log.Trace(fmt.Sprintf("reconnect failed: %v", err))
   461  		return err
   462  	}
   463  	select {
   464  	case c.reconnected <- newconn:
   465  		c.writeConn = newconn
   466  		return nil
   467  	case <-c.didClose:
   468  		newconn.Close()
   469  		return ErrClientQuit
   470  	}
   471  }
   472  
   473  //调度是客户机的主循环。
   474  //它向等待调用和批调用发送读取消息
   475  //注册订阅的订阅通知。
   476  func (c *Client) dispatch(conn net.Conn) {
   477  //生成初始读取循环。
   478  	go c.read(conn)
   479  
   480  	var (
   481  lastOp        *requestOp    //跟踪上次发送操作
   482  requestOpLock = c.requestOp //保持发送锁时为零
   483  reading       = true        //如果为真,则运行读取循环
   484  	)
   485  	defer close(c.didClose)
   486  	defer func() {
   487  		close(c.closing)
   488  		c.closeRequestOps(ErrClientQuit)
   489  		conn.Close()
   490  		if reading {
   491  //清空读取通道,直到读取结束。
   492  			for {
   493  				select {
   494  				case <-c.readResp:
   495  				case <-c.readErr:
   496  					return
   497  				}
   498  			}
   499  		}
   500  	}()
   501  
   502  	for {
   503  		select {
   504  		case <-c.close:
   505  			return
   506  
   507  //读取路径。
   508  		case batch := <-c.readResp:
   509  			for _, msg := range batch {
   510  				switch {
   511  				case msg.isNotification():
   512  					log.Trace("", "msg", log.Lazy{Fn: func() string {
   513  						return fmt.Sprint("<-readResp: notification ", msg)
   514  					}})
   515  					c.handleNotification(msg)
   516  				case msg.isResponse():
   517  					log.Trace("", "msg", log.Lazy{Fn: func() string {
   518  						return fmt.Sprint("<-readResp: response ", msg)
   519  					}})
   520  					c.handleResponse(msg)
   521  				default:
   522  					log.Debug("", "msg", log.Lazy{Fn: func() string {
   523  						return fmt.Sprint("<-readResp: dropping weird message", msg)
   524  					}})
   525  //托多:也许接近
   526  				}
   527  			}
   528  
   529  		case err := <-c.readErr:
   530  			log.Debug("<-readErr", "err", err)
   531  			c.closeRequestOps(err)
   532  			conn.Close()
   533  			reading = false
   534  
   535  		case newconn := <-c.reconnected:
   536  			log.Debug("<-reconnected", "reading", reading, "remote", conn.RemoteAddr())
   537  			if reading {
   538  //等待上一个读取循环退出。这是一个罕见的病例。
   539  				conn.Close()
   540  				<-c.readErr
   541  			}
   542  			go c.read(newconn)
   543  			reading = true
   544  			conn = newconn
   545  
   546  //发送路径。
   547  		case op := <-requestOpLock:
   548  //停止侦听进一步的发送操作,直到当前操作完成。
   549  			requestOpLock = nil
   550  			lastOp = op
   551  			for _, id := range op.ids {
   552  				c.respWait[string(id)] = op
   553  			}
   554  
   555  		case err := <-c.sendDone:
   556  			if err != nil {
   557  //删除上次发送的响应处理程序。我们把它们移到这里
   558  //因为错误已经在call或batchcall中处理。当
   559  //读取循环停止,它将发出所有其他当前操作的信号。
   560  				for _, id := range lastOp.ids {
   561  					delete(c.respWait, string(id))
   562  				}
   563  			}
   564  //再次收听发送操作。
   565  			requestOpLock = c.requestOp
   566  			lastOp = nil
   567  		}
   568  	}
   569  }
   570  
   571  //closerequestops取消阻止挂起的发送操作和活动订阅。
   572  func (c *Client) closeRequestOps(err error) {
   573  	didClose := make(map[*requestOp]bool)
   574  
   575  	for id, op := range c.respWait {
   576  //删除op,以便以后的调用不会再次关闭op.resp。
   577  		delete(c.respWait, id)
   578  
   579  		if !didClose[op] {
   580  			op.err = err
   581  			close(op.resp)
   582  			didClose[op] = true
   583  		}
   584  	}
   585  	for id, sub := range c.subs {
   586  		delete(c.subs, id)
   587  		sub.quitWithError(err, false)
   588  	}
   589  }
   590  
   591  func (c *Client) handleNotification(msg *jsonrpcMessage) {
   592  	if !strings.HasSuffix(msg.Method, notificationMethodSuffix) {
   593  		log.Debug("dropping non-subscription message", "msg", msg)
   594  		return
   595  	}
   596  	var subResult struct {
   597  		ID     string          `json:"subscription"`
   598  		Result json.RawMessage `json:"result"`
   599  	}
   600  	if err := json.Unmarshal(msg.Params, &subResult); err != nil {
   601  		log.Debug("dropping invalid subscription message", "msg", msg)
   602  		return
   603  	}
   604  	if c.subs[subResult.ID] != nil {
   605  		c.subs[subResult.ID].deliver(subResult.Result)
   606  	}
   607  }
   608  
   609  func (c *Client) handleResponse(msg *jsonrpcMessage) {
   610  	op := c.respWait[string(msg.ID)]
   611  	if op == nil {
   612  		log.Debug("unsolicited response", "msg", msg)
   613  		return
   614  	}
   615  	delete(c.respWait, string(msg.ID))
   616  //对于正常响应,只需将响应转发到call/batchcall。
   617  	if op.sub == nil {
   618  		op.resp <- msg
   619  		return
   620  	}
   621  //对于订阅响应,如果服务器
   622  //表示成功。ethsubscribe在任何情况下都可以通过
   623  //Op.Resp频道。
   624  	defer close(op.resp)
   625  	if msg.Error != nil {
   626  		op.err = msg.Error
   627  		return
   628  	}
   629  	if op.err = json.Unmarshal(msg.Result, &op.sub.subid); op.err == nil {
   630  		go op.sub.start()
   631  		c.subs[op.sub.subid] = op.sub
   632  	}
   633  }
   634  
   635  //阅读发生在一个专门的Goroutine上。
   636  
   637  func (c *Client) read(conn net.Conn) error {
   638  	var (
   639  		buf json.RawMessage
   640  		dec = json.NewDecoder(conn)
   641  	)
   642  	readMessage := func() (rs []*jsonrpcMessage, err error) {
   643  		buf = buf[:0]
   644  		if err = dec.Decode(&buf); err != nil {
   645  			return nil, err
   646  		}
   647  		if isBatch(buf) {
   648  			err = json.Unmarshal(buf, &rs)
   649  		} else {
   650  			rs = make([]*jsonrpcMessage, 1)
   651  			err = json.Unmarshal(buf, &rs[0])
   652  		}
   653  		return rs, err
   654  	}
   655  
   656  	for {
   657  		resp, err := readMessage()
   658  		if err != nil {
   659  			c.readErr <- err
   660  			return err
   661  		}
   662  		c.readResp <- resp
   663  	}
   664  }
   665  
   666  //订阅。
   667  
   668  //客户端订阅表示通过ethsubscribe建立的订阅。
   669  type ClientSubscription struct {
   670  	client    *Client
   671  	etype     reflect.Type
   672  	channel   reflect.Value
   673  	namespace string
   674  	subid     string
   675  	in        chan json.RawMessage
   676  
   677  quitOnce sync.Once     //确保退出关闭一次
   678  quit     chan struct{} //退出订阅时将关闭Quit
   679  errOnce  sync.Once     //确保err关闭一次
   680  	err      chan error
   681  }
   682  
   683  func newClientSubscription(c *Client, namespace string, channel reflect.Value) *ClientSubscription {
   684  	sub := &ClientSubscription{
   685  		client:    c,
   686  		namespace: namespace,
   687  		etype:     channel.Type().Elem(),
   688  		channel:   channel,
   689  		quit:      make(chan struct{}),
   690  		err:       make(chan error, 1),
   691  		in:        make(chan json.RawMessage),
   692  	}
   693  	return sub
   694  }
   695  
   696  //err返回订阅错误通道。err的预期用途是
   697  //客户端连接意外关闭时重新订阅。
   698  //
   699  //当订阅到期时,错误通道接收到一个值。
   700  //出错。如果调用了close,则接收到的错误为nil。
   701  //在基础客户端上,没有发生其他错误。
   702  //
   703  //当对订阅调用Unsubscribe时,错误通道将关闭。
   704  func (sub *ClientSubscription) Err() <-chan error {
   705  	return sub.err
   706  }
   707  
   708  //取消订阅取消订阅通知并关闭错误通道。
   709  //它可以安全地被多次调用。
   710  func (sub *ClientSubscription) Unsubscribe() {
   711  	sub.quitWithError(nil, true)
   712  	sub.errOnce.Do(func() { close(sub.err) })
   713  }
   714  
   715  func (sub *ClientSubscription) quitWithError(err error, unsubscribeServer bool) {
   716  	sub.quitOnce.Do(func() {
   717  //调度循环将无法执行取消订阅调用
   718  //如果交货时受阻。关闭Sub.Quit First,因为它
   719  //解除锁定传递。
   720  		close(sub.quit)
   721  		if unsubscribeServer {
   722  			sub.requestUnsubscribe()
   723  		}
   724  		if err != nil {
   725  			if err == ErrClientQuit {
   726  err = nil //遵循订阅语义。
   727  			}
   728  			sub.err <- err
   729  		}
   730  	})
   731  }
   732  
   733  func (sub *ClientSubscription) deliver(result json.RawMessage) (ok bool) {
   734  	select {
   735  	case sub.in <- result:
   736  		return true
   737  	case <-sub.quit:
   738  		return false
   739  	}
   740  }
   741  
   742  func (sub *ClientSubscription) start() {
   743  	sub.quitWithError(sub.forward())
   744  }
   745  
   746  func (sub *ClientSubscription) forward() (err error, unsubscribeServer bool) {
   747  	cases := []reflect.SelectCase{
   748  		{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.quit)},
   749  		{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(sub.in)},
   750  		{Dir: reflect.SelectSend, Chan: sub.channel},
   751  	}
   752  	buffer := list.New()
   753  	defer buffer.Init()
   754  	for {
   755  		var chosen int
   756  		var recv reflect.Value
   757  		if buffer.Len() == 0 {
   758  //空闲,省略发送案例。
   759  			chosen, recv, _ = reflect.Select(cases[:2])
   760  		} else {
   761  //非空缓冲区,发送第一个排队的项目。
   762  			cases[2].Send = reflect.ValueOf(buffer.Front().Value)
   763  			chosen, recv, _ = reflect.Select(cases)
   764  		}
   765  
   766  		switch chosen {
   767  case 0: //<退出
   768  			return nil, false
   769  case 1: //<-in in
   770  			val, err := sub.unmarshal(recv.Interface().(json.RawMessage))
   771  			if err != nil {
   772  				return err, true
   773  			}
   774  			if buffer.Len() == maxClientSubscriptionBuffer {
   775  				return ErrSubscriptionQueueOverflow, true
   776  			}
   777  			buffer.PushBack(val)
   778  case 2: //子通道<
   779  cases[2].Send = reflect.Value{} //不要抓住价值。
   780  			buffer.Remove(buffer.Front())
   781  		}
   782  	}
   783  }
   784  
   785  func (sub *ClientSubscription) unmarshal(result json.RawMessage) (interface{}, error) {
   786  	val := reflect.New(sub.etype)
   787  	err := json.Unmarshal(result, val.Interface())
   788  	return val.Elem().Interface(), err
   789  }
   790  
   791  func (sub *ClientSubscription) requestUnsubscribe() error {
   792  	var result interface{}
   793  	return sub.client.Call(&result, sub.namespace+unsubscribeMethodSuffix, sub.subid)
   794  }
   795