forked from g3n/engine
/
dispatcher.go
132 lines (107 loc) · 3.47 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
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
// Copyright 2016 The G3N Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package core
// Dispatcher implements an event dispatcher
type Dispatcher struct {
evmap map[string][]subscription // maps event name to subcriptions list
cancel bool // flag informing cancelled dispatch
}
// IDispatcher is the interface for dispatchers
type IDispatcher interface {
Subscribe(evname string, cb Callback)
SubscribeID(evname string, id interface{}, cb Callback)
UnsubscribeID(evname string, id interface{}) int
Dispatch(evname string, ev interface{}) bool
ClearSubscriptions()
CancelDispatch()
}
// Callback is the type for the Dispatcher callbacks functions
type Callback func(string, interface{})
type subscription struct {
id interface{}
cb func(string, interface{})
}
// NewDispatcher creates and returns a new Event Dispatcher
func NewDispatcher() *Dispatcher {
d := new(Dispatcher)
d.Initialize()
return d
}
// Initialize initializes this event dispatcher.
// It is normally used by other types which embed an event dispatcher
func (d *Dispatcher) Initialize() {
d.evmap = make(map[string][]subscription)
}
// Subscribe subscribes to receive events with the given name.
// If it is necessary to unsubscribe the event, the function SubscribeID should be used.
func (d *Dispatcher) Subscribe(evname string, cb Callback) {
d.SubscribeID(evname, nil, cb)
}
// SubscribeID subscribes to receive events with the given name.
// The function accepts a unique id to be use to unsubscribe this event
func (d *Dispatcher) SubscribeID(evname string, id interface{}, cb Callback) {
d.evmap[evname] = append(d.evmap[evname], subscription{id, cb})
}
// UnsubscribeID unsubscribes from the specified event and subscription id
// Returns the number of subscriptions found.
func (d *Dispatcher) UnsubscribeID(evname string, id interface{}) int {
// Get list of subscribers for this event
// If not found, nothing to do
subs, ok := d.evmap[evname]
if !ok {
return 0
}
// Remove all subscribers with the specified id for this event
found := 0
pos := 0
for pos < len(subs) {
if subs[pos].id == id {
copy(subs[pos:], subs[pos+1:])
subs[len(subs)-1] = subscription{}
subs = subs[:len(subs)-1]
found++
} else {
pos++
}
}
d.evmap[evname] = subs
return found
}
// UnsubscribeAllID unsubscribes from all events with the specified subscription id.
// Returns the number of subscriptions found.
func (d *Dispatcher) UnsubscribeAllID(id interface{}) int {
total := 0
for evname := range d.evmap {
found := d.UnsubscribeID(evname, id)
total += found
}
return total
}
// Dispatch dispatch the specified event and data to all registered subscribers.
// The function returns true if the propagation was cancelled by a subscriber.
func (d *Dispatcher) Dispatch(evname string, ev interface{}) bool {
// Get list of subscribers for this event
subs := d.evmap[evname]
if subs == nil {
return false
}
// Dispatch to all subscribers
d.cancel = false
for i := 0; i < len(subs); i++ {
subs[i].cb(evname, ev)
if d.cancel {
break
}
}
return d.cancel
}
// ClearSubscriptions clear all subscriptions from this dispatcher
func (d *Dispatcher) ClearSubscriptions() {
d.evmap = make(map[string][]subscription)
}
// CancelDispatch cancels the propagation of the current event.
// No more subscribers will be called for this event dispatch.
func (d *Dispatcher) CancelDispatch() {
d.cancel = true
}