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  }