github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/event/event.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  //</624450090722922496>
    11  
    12  
    13  //包事件处理对实时事件的订阅。
    14  package event
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"reflect"
    20  	"sync"
    21  	"time"
    22  )
    23  
    24  //typemuxevent是一个推送到订户的带有时间标签的通知。
    25  type TypeMuxEvent struct {
    26  	Time time.Time
    27  	Data interface{}
    28  }
    29  
    30  //typemux将事件发送给已注册的接收者。接收器可以
    31  //注册以处理特定类型的事件。任何操作
    32  //在mux停止后调用将返回errmuxClosed。
    33  //
    34  //The zero value is ready to use.
    35  //
    36  //已弃用:使用源
    37  type TypeMux struct {
    38  	mutex   sync.RWMutex
    39  	subm    map[reflect.Type][]*TypeMuxSubscription
    40  	stopped bool
    41  }
    42  
    43  //在已关闭的typemux上发布时返回errmuxClosed。
    44  var ErrMuxClosed = errors.New("event: mux closed")
    45  
    46  //订阅为给定类型的事件创建订阅。这个
    47  //订阅的频道在取消订阅时关闭
    48  //或者MUX关闭。
    49  func (mux *TypeMux) Subscribe(types ...interface{}) *TypeMuxSubscription {
    50  	sub := newsub(mux)
    51  	mux.mutex.Lock()
    52  	defer mux.mutex.Unlock()
    53  	if mux.stopped {
    54  //将状态设置为“已关闭”,以便在此之后调用Unsubscribe
    55  //呼叫将短路。
    56  		sub.closed = true
    57  		close(sub.postC)
    58  	} else {
    59  		if mux.subm == nil {
    60  			mux.subm = make(map[reflect.Type][]*TypeMuxSubscription)
    61  		}
    62  		for _, t := range types {
    63  			rtyp := reflect.TypeOf(t)
    64  			oldsubs := mux.subm[rtyp]
    65  			if find(oldsubs, sub) != -1 {
    66  				panic(fmt.Sprintf("event: duplicate type %s in Subscribe", rtyp))
    67  			}
    68  			subs := make([]*TypeMuxSubscription, len(oldsubs)+1)
    69  			copy(subs, oldsubs)
    70  			subs[len(oldsubs)] = sub
    71  			mux.subm[rtyp] = subs
    72  		}
    73  	}
    74  	return sub
    75  }
    76  
    77  //Post向为给定类型注册的所有接收器发送事件。
    78  //如果MUX已停止,则返回errmuxClosed。
    79  func (mux *TypeMux) Post(ev interface{}) error {
    80  	event := &TypeMuxEvent{
    81  		Time: time.Now(),
    82  		Data: ev,
    83  	}
    84  	rtyp := reflect.TypeOf(ev)
    85  	mux.mutex.RLock()
    86  	if mux.stopped {
    87  		mux.mutex.RUnlock()
    88  		return ErrMuxClosed
    89  	}
    90  	subs := mux.subm[rtyp]
    91  	mux.mutex.RUnlock()
    92  	for _, sub := range subs {
    93  		sub.deliver(event)
    94  	}
    95  	return nil
    96  }
    97  
    98  //停止关闭一个多路复用器。MUX不能再使用了。
    99  //以后的Post调用将失败,并关闭errmuxClose。
   100  //停止块,直到所有当前交货完成。
   101  func (mux *TypeMux) Stop() {
   102  	mux.mutex.Lock()
   103  	for _, subs := range mux.subm {
   104  		for _, sub := range subs {
   105  			sub.closewait()
   106  		}
   107  	}
   108  	mux.subm = nil
   109  	mux.stopped = true
   110  	mux.mutex.Unlock()
   111  }
   112  
   113  func (mux *TypeMux) del(s *TypeMuxSubscription) {
   114  	mux.mutex.Lock()
   115  	for typ, subs := range mux.subm {
   116  		if pos := find(subs, s); pos >= 0 {
   117  			if len(subs) == 1 {
   118  				delete(mux.subm, typ)
   119  			} else {
   120  				mux.subm[typ] = posdelete(subs, pos)
   121  			}
   122  		}
   123  	}
   124  	s.mux.mutex.Unlock()
   125  }
   126  
   127  func find(slice []*TypeMuxSubscription, item *TypeMuxSubscription) int {
   128  	for i, v := range slice {
   129  		if v == item {
   130  			return i
   131  		}
   132  	}
   133  	return -1
   134  }
   135  
   136  func posdelete(slice []*TypeMuxSubscription, pos int) []*TypeMuxSubscription {
   137  	news := make([]*TypeMuxSubscription, len(slice)-1)
   138  	copy(news[:pos], slice[:pos])
   139  	copy(news[pos:], slice[pos+1:])
   140  	return news
   141  }
   142  
   143  //typemux订阅是通过typemux建立的订阅。
   144  type TypeMuxSubscription struct {
   145  	mux     *TypeMux
   146  	created time.Time
   147  	closeMu sync.Mutex
   148  	closing chan struct{}
   149  	closed  bool
   150  
   151  //这两个频道是同一频道。它们分开存放,所以
   152  //post可以设置为nil,而不影响
   153  //陈。
   154  	postMu sync.RWMutex
   155  	readC  <-chan *TypeMuxEvent
   156  	postC  chan<- *TypeMuxEvent
   157  }
   158  
   159  func newsub(mux *TypeMux) *TypeMuxSubscription {
   160  	c := make(chan *TypeMuxEvent)
   161  	return &TypeMuxSubscription{
   162  		mux:     mux,
   163  		created: time.Now(),
   164  		readC:   c,
   165  		postC:   c,
   166  		closing: make(chan struct{}),
   167  	}
   168  }
   169  
   170  func (s *TypeMuxSubscription) Chan() <-chan *TypeMuxEvent {
   171  	return s.readC
   172  }
   173  
   174  func (s *TypeMuxSubscription) Unsubscribe() {
   175  	s.mux.del(s)
   176  	s.closewait()
   177  }
   178  
   179  func (s *TypeMuxSubscription) Closed() bool {
   180  	s.closeMu.Lock()
   181  	defer s.closeMu.Unlock()
   182  	return s.closed
   183  }
   184  
   185  func (s *TypeMuxSubscription) closewait() {
   186  	s.closeMu.Lock()
   187  	defer s.closeMu.Unlock()
   188  	if s.closed {
   189  		return
   190  	}
   191  	close(s.closing)
   192  	s.closed = true
   193  
   194  	s.postMu.Lock()
   195  	close(s.postC)
   196  	s.postC = nil
   197  	s.postMu.Unlock()
   198  }
   199  
   200  func (s *TypeMuxSubscription) deliver(event *TypeMuxEvent) {
   201  //失效事件时短路交付
   202  	if s.created.After(event.Time) {
   203  		return
   204  	}
   205  //否则,交付活动
   206  	s.postMu.RLock()
   207  	defer s.postMu.RUnlock()
   208  
   209  	select {
   210  	case s.postC <- event:
   211  	case <-s.closing:
   212  	}
   213  }
   214