github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/rpc/event/event_bus.go (about) 1 package event 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 ) 8 9 // BusSubscriber defines subscription-related bus behavior 10 type BusSubscriber interface { 11 Subscribe(topic string, fn interface{}) error 12 SubscribeAsync(topic string, fn interface{}, transactional bool) error 13 SubscribeOnce(topic string, fn interface{}) error 14 SubscribeOnceAsync(topic string, fn interface{}) error 15 Unsubscribe(topic string, handler interface{}) error 16 } 17 18 // BusPublisher defines publishing-related bus behavior 19 type BusPublisher interface { 20 Publish(topic string, args ...interface{}) 21 } 22 23 // BusController defines bus control behavior (checking handler's presence, synchronization) 24 type BusController interface { 25 HasCallback(topic string) bool 26 WaitAsync() 27 } 28 29 // IBus a global interface(subscribe, publish, control) bus behavior 30 type IBus interface { 31 BusController 32 BusSubscriber 33 BusPublisher 34 } 35 36 // EventBus - box for handlers and callbacks. 37 type Bus struct { 38 handlers map[string][]*eventHandler 39 lock sync.Mutex // a lock for the map 40 wg sync.WaitGroup 41 } 42 43 type eventHandler struct { 44 callBack reflect.Value 45 flagOnce bool 46 async bool 47 transactional bool 48 sync.Mutex // lock for an event handler - useful for running async callbacks serially 49 } 50 51 // New returns new EventBus with empty handlers. 52 func New() IBus { 53 b := &Bus{ 54 make(map[string][]*eventHandler), 55 sync.Mutex{}, 56 sync.WaitGroup{}, 57 } 58 return IBus(b) 59 } 60 61 // doSubscribe handles the subscription logic and is utilized by the public Subscribe functions 62 func (bus *Bus) doSubscribe(topic string, fn interface{}, handler *eventHandler) error { 63 bus.lock.Lock() 64 defer bus.lock.Unlock() 65 if !(reflect.TypeOf(fn).Kind() == reflect.Func) { 66 return fmt.Errorf("%s is not of type reflect.Func", reflect.TypeOf(fn).Kind()) 67 } 68 bus.handlers[topic] = append(bus.handlers[topic], handler) 69 return nil 70 } 71 72 // Subscribe subscribes to a topic. 73 // Returns error if `fn` is not a function. 74 func (bus *Bus) Subscribe(topic string, fn interface{}) error { 75 return bus.doSubscribe(topic, fn, &eventHandler{ 76 reflect.ValueOf(fn), false, false, false, sync.Mutex{}, 77 }) 78 } 79 80 // SubscribeAsync subscribes to a topic with an asynchronous callback 81 // Transactional determines whether subsequent callbacks for a topic are 82 // run serially (true) or concurrently (false) 83 // Returns error if `fn` is not a function. 84 func (bus *Bus) SubscribeAsync(topic string, fn interface{}, transactional bool) error { 85 return bus.doSubscribe(topic, fn, &eventHandler{ 86 reflect.ValueOf(fn), false, true, transactional, sync.Mutex{}, 87 }) 88 } 89 90 // SubscribeOnce subscribes to a topic once. Handler will be removed after executing. 91 // Returns error if `fn` is not a function. 92 func (bus *Bus) SubscribeOnce(topic string, fn interface{}) error { 93 return bus.doSubscribe(topic, fn, &eventHandler{ 94 reflect.ValueOf(fn), true, false, false, sync.Mutex{}, 95 }) 96 } 97 98 // SubscribeOnceAsync subscribes to a topic once with an asynchronous callback 99 // Handler will be removed after executing. 100 // Returns error if `fn` is not a function. 101 func (bus *Bus) SubscribeOnceAsync(topic string, fn interface{}) error { 102 return bus.doSubscribe(topic, fn, &eventHandler{ 103 reflect.ValueOf(fn), true, true, false, sync.Mutex{}, 104 }) 105 } 106 107 // HasCallback returns true if exists any callback subscribed to the topic. 108 func (bus *Bus) HasCallback(topic string) bool { 109 bus.lock.Lock() 110 defer bus.lock.Unlock() 111 _, ok := bus.handlers[topic] 112 if ok { 113 return len(bus.handlers[topic]) > 0 114 } 115 return false 116 } 117 118 // Unsubscribe removes callback defined for a topic. 119 // Returns error if there are no callbacks subscribed to the topic. 120 func (bus *Bus) Unsubscribe(topic string, handler interface{}) error { 121 bus.lock.Lock() 122 defer bus.lock.Unlock() 123 if _, ok := bus.handlers[topic]; ok && len(bus.handlers[topic]) > 0 { 124 bus.removeHandler(topic, bus.findHandlerIdx(topic, reflect.ValueOf(handler))) 125 return nil 126 } 127 return fmt.Errorf("topic %s doesn't exist", topic) 128 } 129 130 // Publish executes callback defined for a topic. Any additional argument will be transferred to the callback. 131 func (bus *Bus) Publish(topic string, args ...interface{}) { 132 bus.lock.Lock() // will unlock if handler is not found or always after setUpPublish 133 defer bus.lock.Unlock() 134 if handlers, ok := bus.handlers[topic]; ok && 0 < len(handlers) { 135 // Handlers slice may be changed by removeHandler and Unsubscribe during iteration, 136 // so make a copy and iterate the copied slice. 137 copyHandlers := make([]*eventHandler, len(handlers)) 138 copy(copyHandlers, handlers) 139 for i, handler := range copyHandlers { 140 if handler.flagOnce { 141 bus.removeHandler(topic, i) 142 } 143 if !handler.async { 144 bus.doPublish(handler, args...) 145 } else { 146 bus.wg.Add(1) 147 if handler.transactional { 148 bus.lock.Unlock() 149 handler.Lock() 150 bus.lock.Lock() 151 } 152 go bus.doPublishAsync(handler, args...) 153 } 154 } 155 } 156 } 157 158 func (bus *Bus) doPublish(handler *eventHandler, args ...interface{}) { 159 passedArguments := bus.setUpPublish(handler, args...) 160 handler.callBack.Call(passedArguments) 161 } 162 163 func (bus *Bus) doPublishAsync(handler *eventHandler, args ...interface{}) { 164 defer bus.wg.Done() 165 if handler.transactional { 166 defer handler.Unlock() 167 } 168 bus.doPublish(handler, args...) 169 } 170 171 func (bus *Bus) removeHandler(topic string, idx int) { 172 if _, ok := bus.handlers[topic]; !ok { 173 return 174 } 175 l := len(bus.handlers[topic]) 176 177 if !(0 <= idx && idx < l) { 178 return 179 } 180 181 copy(bus.handlers[topic][idx:], bus.handlers[topic][idx+1:]) 182 bus.handlers[topic][l-1] = nil // or the zero value of T 183 bus.handlers[topic] = bus.handlers[topic][:l-1] 184 } 185 186 func (bus *Bus) findHandlerIdx(topic string, callback reflect.Value) int { 187 if _, ok := bus.handlers[topic]; ok { 188 for idx, handler := range bus.handlers[topic] { 189 if handler.callBack.Type() == callback.Type() && 190 handler.callBack.Pointer() == callback.Pointer() { 191 return idx 192 } 193 } 194 } 195 return -1 196 } 197 198 func (bus *Bus) setUpPublish(callback *eventHandler, args ...interface{}) []reflect.Value { 199 funcType := callback.callBack.Type() 200 passedArguments := make([]reflect.Value, len(args)) 201 for i, v := range args { 202 if v == nil { 203 passedArguments[i] = reflect.New(funcType.In(i)).Elem() 204 } else { 205 passedArguments[i] = reflect.ValueOf(v) 206 } 207 } 208 209 return passedArguments 210 } 211 212 // WaitAsync waits for all async callbacks to complete 213 func (bus *Bus) WaitAsync() { 214 bus.wg.Wait() 215 }