forked from hybridgroup/gobot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
eventer.go
155 lines (125 loc) · 3.41 KB
/
eventer.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
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
package gobot
import "sync"
type eventChannel chan *Event
type eventer struct {
// map of valid Event names
eventnames map[string]string
// new events get put in to the event channel
in eventChannel
// map of out channels used by subscribers
outs map[eventChannel]eventChannel
// mutex to protect the eventChannel map
eventsMutex sync.Mutex
}
const eventChanBufferSize = 10
// Eventer is the interface which describes how a Driver or Adaptor
// handles events.
type Eventer interface {
// Events returns the map of valid Event names.
Events() (eventnames map[string]string)
// Event returns an Event string from map of valid Event names.
// Mostly used to validate that an Event name is valid.
Event(name string) string
// AddEvent registers a new Event name.
AddEvent(name string)
// DeleteEvent removes a previously registered Event name.
DeleteEvent(name string)
// Publish new events to any subscriber
Publish(name string, data interface{})
// Subscribe to events
Subscribe() (events eventChannel)
// Unsubscribe from an event channel
Unsubscribe(events eventChannel)
// Event handler
On(name string, f func(s interface{})) (err error)
// Event handler, only executes one time
Once(name string, f func(s interface{})) (err error)
}
// NewEventer returns a new Eventer.
func NewEventer() Eventer {
evtr := &eventer{
eventnames: make(map[string]string),
in: make(eventChannel, eventChanBufferSize),
outs: make(map[eventChannel]eventChannel),
}
// goroutine to cascade "in" events to all "out" event channels
go func() {
for {
select {
case evt := <-evtr.in:
evtr.eventsMutex.Lock()
for _, out := range evtr.outs {
out <- evt
}
evtr.eventsMutex.Unlock()
}
}
}()
return evtr
}
// Events returns the map of valid Event names.
func (e *eventer) Events() map[string]string {
return e.eventnames
}
// Event returns an Event string from map of valid Event names.
// Mostly used to validate that an Event name is valid.
func (e *eventer) Event(name string) string {
return e.eventnames[name]
}
// AddEvent registers a new Event name.
func (e *eventer) AddEvent(name string) {
e.eventnames[name] = name
}
// DeleteEvent removes a previously registered Event name.
func (e *eventer) DeleteEvent(name string) {
delete(e.eventnames, name)
}
// Publish new events to anyone that is subscribed
func (e *eventer) Publish(name string, data interface{}) {
evt := NewEvent(name, data)
e.in <- evt
}
// Subscribe to any events from this eventer
func (e *eventer) Subscribe() eventChannel {
e.eventsMutex.Lock()
defer e.eventsMutex.Unlock()
out := make(eventChannel, eventChanBufferSize)
e.outs[out] = out
return out
}
// Unsubscribe from the event channel
func (e *eventer) Unsubscribe(events eventChannel) {
e.eventsMutex.Lock()
defer e.eventsMutex.Unlock()
delete(e.outs, events)
}
// On executes the event handler f when e is Published to.
func (e *eventer) On(n string, f func(s interface{})) (err error) {
out := e.Subscribe()
go func() {
for {
select {
case evt := <-out:
if evt.Name == n {
f(evt.Data)
}
}
}
}()
return
}
// Once is similar to On except that it only executes f one time.
func (e *eventer) Once(n string, f func(s interface{})) (err error) {
out := e.Subscribe()
go func() {
ProcessEvents:
for evt := range out {
if evt.Name == n {
f(evt.Data)
e.Unsubscribe(out)
break ProcessEvents
}
}
}()
return
}