github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/event/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 event 26 27 import ( 28 "context" 29 "sync" 30 "time" 31 32 "github.com/ethereum/go-ethereum/common/mclock" 33 ) 34 35 //订阅表示事件流。事件的载体通常是 36 //但不是接口的一部分。 37 // 38 //建立订阅时可能失败。通过错误报告失败 39 //通道。如果订阅出现问题(例如 40 //传递事件的网络连接已关闭)。只有一个值 41 //发送。 42 // 43 //当订阅成功结束时(即当 44 //事件源已关闭)。当调用UNSUBSCRIBE时,它也将关闭。 45 // 46 //Unsubscribe方法取消发送事件。您必须呼叫取消订阅 47 //案例以确保与订阅相关的资源被释放。它可以 48 //调用任意次数。 49 type Subscription interface { 50 Err() <-chan error //返回错误通道 51 Unsubscribe() //取消发送事件,关闭错误通道 52 } 53 54 //new subscription在新的goroutine中作为订阅运行producer函数。这个 55 //当调用UNSUBSCRIBE时,将关闭提供给生产者的频道。如果fn返回 56 //错误,它在订阅的错误通道上发送。 57 func NewSubscription(producer func(<-chan struct{}) error) Subscription { 58 s := &funcSub{unsub: make(chan struct{}), err: make(chan error, 1)} 59 go func() { 60 defer close(s.err) 61 err := producer(s.unsub) 62 s.mu.Lock() 63 defer s.mu.Unlock() 64 if !s.unsubscribed { 65 if err != nil { 66 s.err <- err 67 } 68 s.unsubscribed = true 69 } 70 }() 71 return s 72 } 73 74 type funcSub struct { 75 unsub chan struct{} 76 err chan error 77 mu sync.Mutex 78 unsubscribed bool 79 } 80 81 func (s *funcSub) Unsubscribe() { 82 s.mu.Lock() 83 if s.unsubscribed { 84 s.mu.Unlock() 85 return 86 } 87 s.unsubscribed = true 88 close(s.unsub) 89 s.mu.Unlock() 90 //等待生产商关闭。 91 <-s.err 92 } 93 94 func (s *funcSub) Err() <-chan error { 95 return s.err 96 } 97 98 //重复重新订阅呼叫fn以保持已建立的订阅。当 99 //订阅已建立,重新订阅等待失败,然后再次调用fn。这个 100 //过程重复,直到调用取消订阅或活动订阅结束 101 //成功地。 102 // 103 //resubscribe在对fn的调用之间应用回退。调整通话间隔时间 104 //基于错误率,但不会超过backoffmax。 105 func Resubscribe(backoffMax time.Duration, fn ResubscribeFunc) Subscription { 106 s := &resubscribeSub{ 107 waitTime: backoffMax / 10, 108 backoffMax: backoffMax, 109 fn: fn, 110 err: make(chan error), 111 unsub: make(chan struct{}), 112 } 113 go s.loop() 114 return s 115 } 116 117 //resubscribeFunc尝试建立订阅。 118 type ResubscribeFunc func(context.Context) (Subscription, error) 119 120 type resubscribeSub struct { 121 fn ResubscribeFunc 122 err chan error 123 unsub chan struct{} 124 unsubOnce sync.Once 125 lastTry mclock.AbsTime 126 waitTime, backoffMax time.Duration 127 } 128 129 func (s *resubscribeSub) Unsubscribe() { 130 s.unsubOnce.Do(func() { 131 s.unsub <- struct{}{} 132 <-s.err 133 }) 134 } 135 136 func (s *resubscribeSub) Err() <-chan error { 137 return s.err 138 } 139 140 func (s *resubscribeSub) loop() { 141 defer close(s.err) 142 var done bool 143 for !done { 144 sub := s.subscribe() 145 if sub == nil { 146 break 147 } 148 done = s.waitForError(sub) 149 sub.Unsubscribe() 150 } 151 } 152 153 func (s *resubscribeSub) subscribe() Subscription { 154 subscribed := make(chan error) 155 var sub Subscription 156 retry: 157 for { 158 s.lastTry = mclock.Now() 159 ctx, cancel := context.WithCancel(context.Background()) 160 go func() { 161 rsub, err := s.fn(ctx) 162 sub = rsub 163 subscribed <- err 164 }() 165 select { 166 case err := <-subscribed: 167 cancel() 168 if err != nil { 169 //订阅失败,请等待,然后启动下一次尝试。 170 if s.backoffWait() { 171 return nil 172 } 173 continue retry 174 } 175 if sub == nil { 176 panic("event: ResubscribeFunc returned nil subscription and no error") 177 } 178 return sub 179 case <-s.unsub: 180 cancel() 181 return nil 182 } 183 } 184 } 185 186 func (s *resubscribeSub) waitForError(sub Subscription) bool { 187 defer sub.Unsubscribe() 188 select { 189 case err := <-sub.Err(): 190 return err == nil 191 case <-s.unsub: 192 return true 193 } 194 } 195 196 func (s *resubscribeSub) backoffWait() bool { 197 if time.Duration(mclock.Now()-s.lastTry) > s.backoffMax { 198 s.waitTime = s.backoffMax / 10 199 } else { 200 s.waitTime *= 2 201 if s.waitTime > s.backoffMax { 202 s.waitTime = s.backoffMax 203 } 204 } 205 206 t := time.NewTimer(s.waitTime) 207 defer t.Stop() 208 select { 209 case <-t.C: 210 return false 211 case <-s.unsub: 212 return true 213 } 214 } 215 216 //subscriptionScope提供了一种功能,可以一次取消订阅多个订阅。 217 // 218 //对于处理多个订阅的代码,可以方便地使用范围 219 //只需一个电话就可以取消所有订阅。该示例演示了 220 //更大的程序。 221 // 222 //零值已准备好使用。 223 type SubscriptionScope struct { 224 mu sync.Mutex 225 subs map[*scopeSub]struct{} 226 closed bool 227 } 228 229 type scopeSub struct { 230 sc *SubscriptionScope 231 s Subscription 232 } 233 234 //跟踪开始跟踪订阅。如果范围已关闭,则track返回nil。这个 235 //返回订阅是一个包装器。取消订阅包装器将其从 236 //范围。 237 func (sc *SubscriptionScope) Track(s Subscription) Subscription { 238 sc.mu.Lock() 239 defer sc.mu.Unlock() 240 if sc.closed { 241 return nil 242 } 243 if sc.subs == nil { 244 sc.subs = make(map[*scopeSub]struct{}) 245 } 246 ss := &scopeSub{sc, s} 247 sc.subs[ss] = struct{}{} 248 return ss 249 } 250 251 //关闭对所有跟踪订阅的取消订阅的呼叫,并阻止进一步添加到 252 //跟踪集。关闭后要跟踪的调用返回nil。 253 func (sc *SubscriptionScope) Close() { 254 sc.mu.Lock() 255 defer sc.mu.Unlock() 256 if sc.closed { 257 return 258 } 259 sc.closed = true 260 for s := range sc.subs { 261 s.s.Unsubscribe() 262 } 263 sc.subs = nil 264 } 265 266 //count返回跟踪订阅的数目。 267 //它是用来调试的。 268 func (sc *SubscriptionScope) Count() int { 269 sc.mu.Lock() 270 defer sc.mu.Unlock() 271 return len(sc.subs) 272 } 273 274 func (s *scopeSub) Unsubscribe() { 275 s.s.Unsubscribe() 276 s.sc.mu.Lock() 277 defer s.sc.mu.Unlock() 278 delete(s.sc.subs, s) 279 } 280 281 func (s *scopeSub) Err() <-chan error { 282 return s.s.Err() 283 }