github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/rpc/subscription.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  //</624450109681176576>
    11  
    12  
    13  package rpc
    14  
    15  import (
    16  	"context"
    17  	"errors"
    18  	"sync"
    19  )
    20  
    21  var (
    22  //当连接不支持通知时,返回errNotificationsUnsupported。
    23  	ErrNotificationsUnsupported = errors.New("notifications not supported")
    24  //找不到给定ID的通知时返回errNotificationNotFound
    25  	ErrSubscriptionNotFound = errors.New("subscription not found")
    26  )
    27  
    28  //ID定义用于标识RPC订阅的伪随机数。
    29  type ID string
    30  
    31  //订阅由通知程序创建,并与该通知程序紧密相连。客户可以使用
    32  //此订阅要等待客户端的取消订阅请求,请参阅err()。
    33  type Subscription struct {
    34  	ID        ID
    35  	namespace string
    36  err       chan error //取消订阅时关闭
    37  }
    38  
    39  //err返回当客户端发送取消订阅请求时关闭的通道。
    40  func (s *Subscription) Err() <-chan error {
    41  	return s.err
    42  }
    43  
    44  //notifierkey用于在连接上下文中存储通知程序。
    45  type notifierKey struct{}
    46  
    47  //通知程序与支持订阅的RPC连接紧密相连。
    48  //服务器回调使用通知程序发送通知。
    49  type Notifier struct {
    50  	codec    ServerCodec
    51  	subMu    sync.Mutex
    52  	active   map[ID]*Subscription
    53  	inactive map[ID]*Subscription
    54  buffer   map[ID][]interface{} //未发送的非活动订阅通知
    55  }
    56  
    57  //NewNotifier创建可用于发送订阅的新通知程序
    58  //通知客户端。
    59  func newNotifier(codec ServerCodec) *Notifier {
    60  	return &Notifier{
    61  		codec:    codec,
    62  		active:   make(map[ID]*Subscription),
    63  		inactive: make(map[ID]*Subscription),
    64  		buffer:   make(map[ID][]interface{}),
    65  	}
    66  }
    67  
    68  //notifierFromContext返回存储在CTX中的notifier值(如果有)。
    69  func NotifierFromContext(ctx context.Context) (*Notifier, bool) {
    70  	n, ok := ctx.Value(notifierKey{}).(*Notifier)
    71  	return n, ok
    72  }
    73  
    74  //CreateSubscription返回耦合到
    75  //RPC连接。默认情况下,订阅不活动,通知
    76  //删除,直到订阅标记为活动。这样做了
    77  //由RPC服务器在订阅ID发送到客户端之后发送。
    78  func (n *Notifier) CreateSubscription() *Subscription {
    79  	s := &Subscription{ID: NewID(), err: make(chan error)}
    80  	n.subMu.Lock()
    81  	n.inactive[s.ID] = s
    82  	n.subMu.Unlock()
    83  	return s
    84  }
    85  
    86  //通知将给定数据作为有效负载发送给客户机。
    87  //如果发生错误,则关闭RPC连接并返回错误。
    88  func (n *Notifier) Notify(id ID, data interface{}) error {
    89  	n.subMu.Lock()
    90  	defer n.subMu.Unlock()
    91  
    92  	if sub, active := n.active[id]; active {
    93  		n.send(sub, data)
    94  	} else {
    95  		n.buffer[id] = append(n.buffer[id], data)
    96  	}
    97  	return nil
    98  }
    99  
   100  func (n *Notifier) send(sub *Subscription, data interface{}) error {
   101  	notification := n.codec.CreateNotification(string(sub.ID), sub.namespace, data)
   102  	err := n.codec.Write(notification)
   103  	if err != nil {
   104  		n.codec.Close()
   105  	}
   106  	return err
   107  }
   108  
   109  //CLOSED返回在RPC连接关闭时关闭的通道。
   110  func (n *Notifier) Closed() <-chan interface{} {
   111  	return n.codec.Closed()
   112  }
   113  
   114  //取消订阅订阅。
   115  //如果找不到订阅,则返回errscriptionNotFound。
   116  func (n *Notifier) unsubscribe(id ID) error {
   117  	n.subMu.Lock()
   118  	defer n.subMu.Unlock()
   119  	if s, found := n.active[id]; found {
   120  		close(s.err)
   121  		delete(n.active, id)
   122  		return nil
   123  	}
   124  	return ErrSubscriptionNotFound
   125  }
   126  
   127  //激活启用订阅。在启用订阅之前
   128  //通知被删除。此方法由RPC服务器在
   129  //订阅ID已发送到客户端。这将阻止通知
   130  //在将订阅ID发送到客户端之前发送到客户端。
   131  func (n *Notifier) activate(id ID, namespace string) {
   132  	n.subMu.Lock()
   133  	defer n.subMu.Unlock()
   134  
   135  	if sub, found := n.inactive[id]; found {
   136  		sub.namespace = namespace
   137  		n.active[id] = sub
   138  		delete(n.inactive, id)
   139  //发送缓冲通知。
   140  		for _, data := range n.buffer[id] {
   141  			n.send(sub, data)
   142  		}
   143  		delete(n.buffer, id)
   144  	}
   145  }
   146