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