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