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