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 }