-
Notifications
You must be signed in to change notification settings - Fork 69
Expand file tree
/
Copy pathmanager.go
More file actions
331 lines (282 loc) · 7.86 KB
/
manager.go
File metadata and controls
331 lines (282 loc) · 7.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
package event
import (
"reflect"
"sync"
)
const (
defaultChannelSize = 100
defaultConsumerNum = 3
)
// Manager event manager definition. for manage events and listeners
type Manager struct {
Options
sync.Mutex
wg sync.WaitGroup
ch chan Event
oc sync.Once
err error // latest error
// name of the manager
name string
// pool sync.Pool
// is a sample for new BasicEvent
sample *BasicEvent
// storage user custom Event instance. you can pre-define some Event instances.
events map[string]Event
// storage user pre-defined event factory func.
eventFc map[string]FactoryFunc
// storage all event name and ListenerQueue map
listeners map[string]*ListenerQueue
// storage all event names by listened
listenedNames map[string]int
}
// NewM create event manager. alias of the NewManager()
func NewM(name string, fns ...OptionFn) *Manager {
return NewManager(name, fns...)
}
// NewManager create event manager
func NewManager(name string, fns ...OptionFn) *Manager {
em := &Manager{
name: name,
// ctx: context.Background(),
// sample event
sample: &BasicEvent{},
// events storage
eventFc: make(map[string]FactoryFunc),
// listeners
listeners: make(map[string]*ListenerQueue),
listenedNames: make(map[string]int),
}
// em.EnableLock = true
// for async fire by goroutine
em.ConsumerNum = defaultConsumerNum
em.ChannelSize = defaultChannelSize
// apply options
return em.WithOptions(fns...)
}
// WithOptions create event manager with options
func (em *Manager) WithOptions(fns ...OptionFn) *Manager {
for _, fn := range fns {
fn(&em.Options)
}
return em
}
/*************************************************************
* region Register listeners
*************************************************************/
// AddListener register an event handler/listener. alias of the method On()
func (em *Manager) AddListener(name string, listener Listener, priority ...int) {
em.On(name, listener, priority...)
}
// Listen register an event handler/listener. alias of the On()
func (em *Manager) Listen(name string, listener Listener, priority ...int) {
em.On(name, listener, priority...)
}
// Once register an event handler/listener. trigger once.
func (em *Manager) Once(name string, listener Listener, priority ...int) {
var listenerOnce Listener
listenerOnce = ListenerFunc(func(e Event) error {
em.RemoveListener(name, listenerOnce)
return listener.Handle(e)
})
em.On(name, listenerOnce, priority...)
}
// On register a event handler/listener. can setting priority.
//
// Usage:
//
// em.On("evt0", listener)
// em.On("evt0", listener, High)
func (em *Manager) On(name string, listener Listener, priority ...int) {
pv := Normal
if len(priority) > 0 {
pv = priority[0]
}
em.addListenerItem(name, &ListenerItem{pv, listener})
}
// Subscribe add events by subscriber interface. alias of the AddSubscriber()
func (em *Manager) Subscribe(sbr Subscriber) {
em.AddSubscriber(sbr)
}
// AddSubscriber add events by subscriber interface.
//
// you can register multi event listeners in a struct func.
// more usage please see README or tests.
func (em *Manager) AddSubscriber(sbr Subscriber) {
for name, listener := range sbr.SubscribedEvents() {
switch lt := listener.(type) {
case Listener:
em.On(name, lt)
// case ListenerFunc:
// em.On(name, lt)
case ListenerItem:
em.addListenerItem(name, <)
default:
panic("event: the value must be an Listener or ListenerItem instance")
}
}
}
func (em *Manager) addListenerItem(name string, li *ListenerItem) {
name = goodName(name, true)
if li.Listener == nil {
panicf("event: the event %q listener cannot be empty", name)
}
if reflect.ValueOf(li.Listener).Kind() == reflect.Struct {
panicf("event: %q - struct listener must be pointer", name)
}
// exists, append it.
if lq, ok := em.listeners[name]; ok {
lq.Push(li)
} else { // first add.
em.listenedNames[name] = 1
em.listeners[name] = (&ListenerQueue{}).Push(li)
}
}
/*************************************************************
* region Event Manage
*************************************************************/
// AddEvent add a pre-defined event instance to manager.
func (em *Manager) AddEvent(e Event) error {
name, err := goodNameOrErr(e.Name(), false)
if err != nil {
return err
}
if ec, ok := e.(Cloneable); ok {
em.addEventFc(name, func() Event {
return ec.Clone()
})
} else {
em.addEventFc(name, func() Event {
return e
})
}
return nil
}
// AddEventFc add a pre-defined event factory func to manager.
func (em *Manager) AddEventFc(name string, fc FactoryFunc) (err error) {
name, err = goodNameOrErr(name, false)
if err == nil {
em.addEventFc(name, fc)
}
return err
}
func (em *Manager) addEventFc(name string, fc FactoryFunc) {
em.Lock()
em.eventFc[name] = fc
em.Unlock()
}
// GetEvent get a pre-defined event instance by name
func (em *Manager) GetEvent(name string) (e Event, ok bool) {
fc, ok := em.eventFc[name]
if ok {
return fc(), true
}
return
}
// HasEvent has pre-defined event check
func (em *Manager) HasEvent(name string) bool {
_, ok := em.eventFc[name]
return ok
}
// RemoveEvent delete pre-define Event by name
func (em *Manager) RemoveEvent(name string) {
if _, ok := em.eventFc[name]; ok {
delete(em.eventFc, name)
}
}
// RemoveEvents remove all registered events
func (em *Manager) RemoveEvents() {
em.eventFc = map[string]FactoryFunc{}
}
/*************************************************************
* region Helper Methods
*************************************************************/
// newBasicEvent create new BasicEvent by clone em.sample
func (em *Manager) newBasicEvent(name string, data M) *BasicEvent {
var cp = *em.sample
cp.SetName(name)
cp.SetData(data)
return &cp
}
// HasListeners check has direct listeners for the event name.
func (em *Manager) HasListeners(name string) bool {
_, ok := em.listenedNames[name]
return ok
}
// Listeners get all listeners
func (em *Manager) Listeners() map[string]*ListenerQueue { return em.listeners }
// ListenersByName get listeners by given event name
func (em *Manager) ListenersByName(name string) *ListenerQueue {
return em.listeners[name]
}
// ListenersCount get listeners number for the event name.
func (em *Manager) ListenersCount(name string) int {
if lq, ok := em.listeners[name]; ok {
return lq.Len()
}
return 0
}
// ListenedNames get listened event names
func (em *Manager) ListenedNames() map[string]int {
return em.listenedNames
}
// RemoveListener remove a given listener, you can limit event name.
//
// Usage:
//
// RemoveListener("", listener)
// RemoveListener("name", listener) // limit event name.
func (em *Manager) RemoveListener(name string, listener Listener) {
if name != "" {
if lq, ok := em.listeners[name]; ok {
lq.Remove(listener)
// delete from manager
if lq.IsEmpty() {
delete(em.listeners, name)
delete(em.listenedNames, name)
}
}
return
}
// name is empty. find all listener and remove matched.
for name, lq := range em.listeners {
lq.Remove(listener)
// delete from manager
if lq.IsEmpty() {
delete(em.listeners, name)
delete(em.listenedNames, name)
}
}
}
// RemoveListeners remove listeners by given name
func (em *Manager) RemoveListeners(name string) {
_, ok := em.listenedNames[name]
if ok {
em.listeners[name].Clear()
// delete from manager
delete(em.listeners, name)
delete(em.listenedNames, name)
}
}
// Clear alias of the Reset()
func (em *Manager) Clear() { em.Reset() }
// Close event channel, deny to fire new event.
func (em *Manager) Close() error {
if em.ch != nil {
close(em.ch)
}
return nil
}
// Reset the manager, clear all data.
func (em *Manager) Reset() {
// clear all listeners
for _, lq := range em.listeners {
lq.Clear()
}
// reset all
em.ch = nil
em.oc = sync.Once{}
em.wg = sync.WaitGroup{}
em.eventFc = make(map[string]FactoryFunc)
em.listeners = make(map[string]*ListenerQueue)
em.listenedNames = make(map[string]int)
}