-
Notifications
You must be signed in to change notification settings - Fork 0
/
event.go
140 lines (125 loc) · 3.35 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
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
package event
import (
"errors"
"fmt"
"reflect"
)
//New generate a new producer
func New(name string) *Producer {
return &Producer{
Name: name,
subscriberContainer: make(map[string][]*subsciber),
}
}
type subsciber struct {
event string
fn reflect.Value
parametes []reflect.Type
}
func newSubscriber(event string, fn reflect.Value, inTypes []reflect.Type) *subsciber {
return &subsciber{
event: event,
fn: fn,
parametes: inTypes,
}
}
// Producer which produces the events
type Producer struct {
Name string
subscriberContainer map[string][]*subsciber
}
// AddListener add a listener for a name-specified event
func (p *Producer) AddListener(callback interface{}) error {
funcVal, parametersType, err := p.precheckListenerCallback(callback)
if err != nil {
return err
}
name := p.Name
sub := newSubscriber(name, funcVal, parametersType)
exists, ok := p.subscriberContainer[name]
if !ok {
exists = []*subsciber{sub}
} else {
exists = append(exists, sub)
}
p.subscriberContainer[name] = exists
return nil
}
//Fire produce a name-specified event, wait to the subscriber to execute.
func (p *Producer) Fire(params ...interface{}) {
p.dispatchEvent(p.Name, params...)
}
// AsyncFire make async call for the subscriber to execute.
func (p *Producer) AsyncFire(name string, params ...interface{}) {
go p.dispatchEvent(name, params...)
}
func (p *Producer) dispatchEvent(name string, params ...interface{}) {
subscribers, exist := p.subscriberContainer[name]
if !exist {
fmt.Println("no subscriber for event:", name)
return
}
types, values := p.checkActualParameters(params...)
hasSubscriber := false
for _, sub := range subscribers {
if p.typesMatchSubscriber(types, sub.parametes) {
sub.fn.Call(values)
hasSubscriber = true
}
}
if !hasSubscriber {
fmt.Printf("it seems that no subscriber for event [%s]\n", name)
}
}
func (p *Producer) precheckListenerCallback(callback interface{}) (reflect.Value, []reflect.Type, error) {
var funcVal reflect.Value
if getType(callback) != reflect.Func {
return funcVal, nil, errors.New("the callback should be a func")
}
funcVal = reflect.ValueOf(callback)
types := p.getParameterTypes(funcVal)
return funcVal, types, nil
}
func (p *Producer) getParameterTypes(callback reflect.Value) []reflect.Type {
callbackType := callback.Type()
parameterSize := callbackType.NumIn()
if parameterSize == 0 {
return nil
}
result := make([]reflect.Type, 0, parameterSize)
for i := 0; i < parameterSize; i++ {
result = append(result, callbackType.In(i))
}
return result
}
func (p *Producer) checkActualParameters(params ...interface{}) ([]reflect.Type, []reflect.Value) {
if len(params) == 0 {
return nil, nil
}
types := make([]reflect.Type, 0, len(params))
values := make([]reflect.Value, 0, len(params))
for _, param := range params {
val := reflect.ValueOf(param)
values = append(values, val)
types = append(types, val.Type())
}
return types, values
}
func (p *Producer) typesMatchSubscriber(actual []reflect.Type, def []reflect.Type) bool {
if actual == nil && def == nil {
return true
}
if len(actual) != len(def) {
return false
}
for i := range actual {
if actual[i] != def[i] {
return false
}
}
return true
}
// return reflect the reflect.Kind Value
func getType(i interface{}) reflect.Kind {
return reflect.TypeOf(i).Kind()
}