github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/utilities/event/event.go (about)

     1  package event
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sync"
     8  	"time"
     9  )
    10  
    11  type TypeMuxEvent struct {
    12  	Time time.Time
    13  	Data interface{}
    14  }
    15  
    16  type TypeMux struct {
    17  	mutex   sync.RWMutex
    18  	subm    map[reflect.Type][]*TypeMuxSubscription
    19  	stopped bool
    20  }
    21  
    22  var ErrMuxClosed = errors.New("event: mux closed")
    23  
    24  func (mux *TypeMux) Subscribe(types ...interface{}) *TypeMuxSubscription {
    25  	sub := newsub(mux)
    26  	mux.mutex.Lock()
    27  	defer mux.mutex.Unlock()
    28  	if mux.stopped {
    29  
    30  		sub.closed = true
    31  		close(sub.postC)
    32  	} else {
    33  		if mux.subm == nil {
    34  			mux.subm = make(map[reflect.Type][]*TypeMuxSubscription)
    35  		}
    36  		for _, t := range types {
    37  			rtyp := reflect.TypeOf(t)
    38  			oldsubs := mux.subm[rtyp]
    39  			if find(oldsubs, sub) != -1 {
    40  				panic(fmt.Sprintf("event: duplicate type %s in Subscribe", rtyp))
    41  			}
    42  			subs := make([]*TypeMuxSubscription, len(oldsubs)+1)
    43  			copy(subs, oldsubs)
    44  			subs[len(oldsubs)] = sub
    45  			mux.subm[rtyp] = subs
    46  		}
    47  	}
    48  	return sub
    49  }
    50  
    51  func (mux *TypeMux) Post(ev interface{}) error {
    52  	event := &TypeMuxEvent{
    53  		Time: time.Now(),
    54  		Data: ev,
    55  	}
    56  	rtyp := reflect.TypeOf(ev)
    57  	mux.mutex.RLock()
    58  	if mux.stopped {
    59  		mux.mutex.RUnlock()
    60  		return ErrMuxClosed
    61  	}
    62  	subs := mux.subm[rtyp]
    63  	mux.mutex.RUnlock()
    64  	for _, sub := range subs {
    65  		sub.deliver(event)
    66  	}
    67  	return nil
    68  }
    69  
    70  func (mux *TypeMux) Stop() {
    71  	mux.mutex.Lock()
    72  	for _, subs := range mux.subm {
    73  		for _, sub := range subs {
    74  			sub.closewait()
    75  		}
    76  	}
    77  	mux.subm = nil
    78  	mux.stopped = true
    79  	mux.mutex.Unlock()
    80  }
    81  
    82  func (mux *TypeMux) del(s *TypeMuxSubscription) {
    83  	mux.mutex.Lock()
    84  	for typ, subs := range mux.subm {
    85  		if pos := find(subs, s); pos >= 0 {
    86  			if len(subs) == 1 {
    87  				delete(mux.subm, typ)
    88  			} else {
    89  				mux.subm[typ] = posdelete(subs, pos)
    90  			}
    91  		}
    92  	}
    93  	s.mux.mutex.Unlock()
    94  }
    95  
    96  func find(slice []*TypeMuxSubscription, item *TypeMuxSubscription) int {
    97  	for i, v := range slice {
    98  		if v == item {
    99  			return i
   100  		}
   101  	}
   102  	return -1
   103  }
   104  
   105  func posdelete(slice []*TypeMuxSubscription, pos int) []*TypeMuxSubscription {
   106  	news := make([]*TypeMuxSubscription, len(slice)-1)
   107  	copy(news[:pos], slice[:pos])
   108  	copy(news[pos:], slice[pos+1:])
   109  	return news
   110  }
   111  
   112  type TypeMuxSubscription struct {
   113  	mux     *TypeMux
   114  	created time.Time
   115  	closeMu sync.Mutex
   116  	closing chan struct{}
   117  	closed  bool
   118  
   119  	postMu sync.RWMutex
   120  	readC  <-chan *TypeMuxEvent
   121  	postC  chan<- *TypeMuxEvent
   122  }
   123  
   124  func newsub(mux *TypeMux) *TypeMuxSubscription {
   125  	c := make(chan *TypeMuxEvent)
   126  	return &TypeMuxSubscription{
   127  		mux:     mux,
   128  		created: time.Now(),
   129  		readC:   c,
   130  		postC:   c,
   131  		closing: make(chan struct{}),
   132  	}
   133  }
   134  
   135  func (s *TypeMuxSubscription) Chan() <-chan *TypeMuxEvent {
   136  	return s.readC
   137  }
   138  
   139  func (s *TypeMuxSubscription) Unsubscribe() {
   140  	s.mux.del(s)
   141  	s.closewait()
   142  }
   143  
   144  func (s *TypeMuxSubscription) Closed() bool {
   145  	s.closeMu.Lock()
   146  	defer s.closeMu.Unlock()
   147  	return s.closed
   148  }
   149  
   150  func (s *TypeMuxSubscription) closewait() {
   151  	s.closeMu.Lock()
   152  	defer s.closeMu.Unlock()
   153  	if s.closed {
   154  		return
   155  	}
   156  	close(s.closing)
   157  	s.closed = true
   158  
   159  	s.postMu.Lock()
   160  	close(s.postC)
   161  	s.postC = nil
   162  	s.postMu.Unlock()
   163  }
   164  
   165  func (s *TypeMuxSubscription) deliver(event *TypeMuxEvent) {
   166  
   167  	if s.created.After(event.Time) {
   168  		return
   169  	}
   170  
   171  	s.postMu.RLock()
   172  	defer s.postMu.RUnlock()
   173  
   174  	select {
   175  	case s.postC <- event:
   176  	case <-s.closing:
   177  	}
   178  }