github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/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 }