-
Notifications
You must be signed in to change notification settings - Fork 0
/
cnator.go
98 lines (75 loc) · 2.15 KB
/
cnator.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
package cnator
import (
"reflect"
)
type (
Cnator struct {
subscriptions map[interface{}][]interface{}
}
)
func New() *Cnator {
return &Cnator{
subscriptions: make(map[interface{}][]interface{}),
}
}
func (c *Cnator) Subscribe(channel interface{}, subscriber interface{}) {
channelType := validateChannel(channel)
validateSubsciber(subscriber, channelType)
c.subscriptions[channel] = append(c.subscriptions[channel], subscriber)
}
func (c *Cnator) Serve() {
for channel, subscibers := range c.subscriptions {
go func(channel interface{}, subscibers []interface{}) {
channelVal := reflect.ValueOf(channel)
for {
channelData, ok := channelVal.Recv()
if !ok {
return
}
for _, subscriber := range subscibers {
subcriberVal := reflect.ValueOf(subscriber)
channelType := reflect.TypeOf(channel)
args := []reflect.Value{}
if channelType.Elem().Name() != "" {
args = []reflect.Value{channelData}
}
subcriberVal.Call(args)
}
}
}(channel, subscibers)
}
}
func validateChannel(channel interface{}) reflect.Type {
channelType := reflect.TypeOf(channel)
if channelType.Kind() != reflect.Chan {
panic("channel parameter is not a channel")
}
if reflect.ValueOf(channel).IsNil() {
panic("channel is uninitialized")
}
return channelType
}
func validateSubsciber(subscriber interface{}, channelType reflect.Type) {
if reflect.ValueOf(subscriber).IsNil() {
panic("subscriber is uninitialized")
}
subscriberType := reflect.TypeOf(subscriber)
if subscriberType.Kind() != reflect.Func {
panic("subscriber must be a function")
}
channelParamType := channelType.Elem().Name()
subscriberParams := subscriberType.NumIn()
if channelParamType == "" {
if subscriberParams != 0 {
panic("channel is empty struct, so subscriber should not have any parameter")
}
} else {
if subscriberParams != 1 {
panic("subscriber must have one and only one parameter")
}
subscriberParamType := subscriberType.In(0).Name()
if channelParamType != subscriberParamType {
panic("subscriber " + subscriberType.String() + " has different param type than the channel: " + channelParamType)
}
}
}