-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevent.go
83 lines (68 loc) · 2.15 KB
/
event.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
// Package event provides the necessary functionality for subscribing to events
// and get notified when they happen.
package event
import (
"strings"
"sync"
)
const namespaceSeparator string = "."
type callback func(interface{}) (propagate bool)
// Dispatcher holds all events.
type Dispatcher struct {
mu sync.RWMutex
events map[string][]callback
}
// NewDispatcher returns a new event dispatcher.
func NewDispatcher() *Dispatcher {
d := &Dispatcher{}
d.events = make(map[string][]callback)
return d
}
// On is used when an callback wants to subscribe to an event.
// Wildcard events are supported when a wildcard
// is the suffix of the name. For example:
// "event.*" is supported
// "event.*.name is not supported
func (d *Dispatcher) On(name string, fn callback) {
name = strings.TrimSuffix(name, "*")
d.mu.Lock()
defer d.mu.Unlock()
// Initialize the events map, in case the dispatcher was created
// using `var dispatcher event.Dispatcher` or `dispatcher := event.Dispatcher{}`
if d.events == nil {
d.events = make(map[string][]callback)
}
d.events[name] = append(d.events[name], fn)
}
// Dispatch passes the Event data to all listeners that have subscribed
// to the event the name parameter equals to. Wildcard listeners of the parent namespace
// will also receive the event. For example, a dispatched event with name "event.test"
// will be received by the listeners of "event.test" and "event.*".
// The "." character is removed from the end of the event name,
// so a name like "event." becomes "event".
func (d *Dispatcher) Dispatch(name string, ev interface{}) {
name = strings.TrimSuffix(name, namespaceSeparator)
d.mu.RLock()
defer d.mu.RUnlock()
// Check wildcard events.
var events []callback
if pos := strings.LastIndex(name, namespaceSeparator); pos > 0 {
prefix := name[:pos+1]
if _events, ok := d.events[prefix]; ok {
events = append(events, _events...)
}
}
// Check events whose name matches with the dispatched event name.
if _events, ok := d.events[name]; ok {
events = append(events, _events...)
}
if len(events) == 0 {
return
}
for _, fn := range events {
if !fn(ev) {
// stop propagation
break
}
}
}