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