This repository has been archived by the owner on Nov 9, 2022. It is now read-only.
/
events.go
85 lines (67 loc) · 1.77 KB
/
events.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
package cord
import (
"sync"
"github.com/WatchBeam/cord/events"
)
type handlerList []events.Handler
func (h handlerList) Delete(handler events.Handler) []events.Handler {
for i, other := range h {
if other != handler {
continue
}
h[i] = h[len(h)-1]
h[len(h)-1] = nil
return h[:len(h)-1]
}
return h
}
// emitter is a simple eventemitter-like interface which
// contains events.Handler interfaces.
type emitter struct {
mu *sync.Mutex
onces map[string]handlerList
handlers map[string]handlerList
}
func newEmitter() emitter {
return emitter{
mu: new(sync.Mutex),
onces: make(map[string]handlerList),
handlers: make(map[string]handlerList),
}
}
// On attaches a events.Handler so that it's called every time an event is received.
func (e *emitter) On(h events.Handler) {
e.mu.Lock()
defer e.mu.Unlock()
e.handlers[h.Name()] = append(e.handlers[h.Name()], h)
}
// Onces attaches a handler that's called the next time the event is received,
// then immediately removed.
func (e *emitter) Once(h events.Handler) {
e.mu.Lock()
defer e.mu.Unlock()
e.onces[h.Name()] = append(e.onces[h.Name()], h)
}
// Off removes a listening handler.
func (e *emitter) Off(h events.Handler) {
e.mu.Lock()
defer e.mu.Unlock()
e.handlers[h.Name()] = e.handlers[h.Name()].Delete(h)
e.onces[h.Name()] = e.onces[h.Name()].Delete(h)
}
// Dispatch invokes all handlers listening on the event with the `b` bytes.
func (e *emitter) Dispatch(event string, b []byte) error {
e.mu.Lock()
l1, l2 := e.handlers[event], e.onces[event]
e.onces[event] = nil
list := make([]events.Handler, len(l1)+len(l2))
copy(list, l1)
copy(list[len(l1):], l2)
e.mu.Unlock()
for _, handler := range list {
if err := handler.Invoke(b); err != nil {
return err
}
}
return nil
}