-
Notifications
You must be signed in to change notification settings - Fork 1
/
dispatcher.go
89 lines (73 loc) · 1.89 KB
/
dispatcher.go
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
package dispatcher
import (
"context"
"fmt"
"regexp"
"sync"
)
// EventType defines the kind of the dispatched event.
type EventType string
// String returns the converted name of the event.
func (et EventType) String() string {
return string(et)
}
// Event defines the type and the data of an event.
type Event interface {
Type() EventType
Data() interface{}
}
// ListenerFunc is a function that can receive events.
type ListenerFunc func(context.Context, Event)
// Dispatcher is an event dispatcher.
type Dispatcher interface {
// On registers an event listener to events of a given type.
On(EventType, ListenerFunc)
// Dispatch fires an event of a given type.
Dispatch(context.Context, Event)
}
// listeners is the internal representation of a list of listeners.
type listeners map[EventType][]*ListenerFunc
// Get retrieves all listeners from a given EventType.
func (l *listeners) Get(et EventType) []*ListenerFunc {
var res []*ListenerFunc
for i, fns := range *l {
if ok, _ := regexp.MatchString(fmt.Sprintf("^%s$", i.String()), et.String()); ok {
res = append(res, fns...)
}
}
return res
}
// Add groups listeners by EventType.
func (l listeners) Add(et EventType, fn *ListenerFunc) {
fns := l.Get(et)
fns = append(fns, fn)
l[et] = fns
}
// dispatcher is the internal implementation of Dispatcher.
type dispatcher struct {
listeners *listeners
}
// New creates a new Dispatcher instance.
func New() Dispatcher {
return &dispatcher{
listeners: &listeners{},
}
}
// On registers an event listener to events of a given type.
func (d *dispatcher) On(et EventType, l ListenerFunc) {
d.listeners.Add(et, &l)
}
// Dispatch fires an event of a given type.
func (d *dispatcher) Dispatch(ctx context.Context, e Event) {
fns := d.listeners.Get(e.Type())
var wg sync.WaitGroup
wg.Add(len(fns))
for _, fn := range fns {
x := *fn
go func() {
x(ctx, e)
wg.Done()
}()
}
wg.Wait()
}