aboutsummaryrefslogtreecommitdiffstats
path: root/eventer/eventer.go
blob: 6e5ee2ec57c54b6316048761554f36a57f32b43a (plain) (blame)
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
package eventer

import "sync"

// Basic receiver interface.
type Receiver interface {
    Send(Event)
}

// Receiver as channel
type Channel chan Event

func (self Channel) Send(ev Event) {
    self <- ev
}

// Receiver as function
type Function func(ev Event)

func (self Function) Send(ev Event) {
    self(ev)
}

type Event struct {
    Type string
    Data interface{}
}

type Channels map[string][]Receiver

type EventMachine struct {
    mu       sync.RWMutex
    channels Channels
}

func New() *EventMachine {
    return &EventMachine{channels: make(Channels)}
}

func (self *EventMachine) add(typ string, r Receiver) {
    self.mu.Lock()
    self.channels[typ] = append(self.channels[typ], r)
    self.mu.Unlock()
}

// Generalised methods for the known receiver types
// * Channel
// * Function
func (self *EventMachine) On(typ string, r interface{}) {
    if eventFunc, ok := r.(func(Event)); ok {
        self.RegisterFunc(typ, eventFunc)
    } else if eventChan, ok := r.(Channel); ok {
        self.RegisterChannel(typ, eventChan)
    } else {
        panic("Invalid type for EventMachine::On")
    }
}

func (self *EventMachine) RegisterChannel(typ string, c Channel) {
    self.add(typ, c)
}

func (self *EventMachine) RegisterFunc(typ string, f Function) {
    self.add(typ, f)
}

func (self *EventMachine) Register(typ string) Channel {
    c := make(Channel, 1)
    self.add(typ, c)
    return c
}

func (self *EventMachine) Post(typ string, data interface{}) {
    self.mu.RLock()
    if self.channels[typ] != nil {
        ev := Event{typ, data}
        for _, receiver := range self.channels[typ] {
            // Blocking is OK. These are internals and need to be handled
            receiver.Send(ev)
        }
    }
    self.mu.RUnlock()
}