aboutsummaryrefslogtreecommitdiffstats
path: root/ethutil/reactor.go
blob: 7cf1452456e22ebf2af1f6e20003d14df8440e3d (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
84
85
86
87
package ethutil

import (
    "sync"
)

type ReactorEvent struct {
    mut   sync.Mutex
    event string
    chans []chan React
}

// Post the specified reactor resource on the channels
// currently subscribed
func (e *ReactorEvent) Post(react React) {
    e.mut.Lock()
    defer e.mut.Unlock()

    for _, ch := range e.chans {
        go func(ch chan React) {
            ch <- react
        }(ch)
    }
}

// Add a subscriber to this event
func (e *ReactorEvent) Add(ch chan React) {
    e.mut.Lock()
    defer e.mut.Unlock()

    e.chans = append(e.chans, ch)
}

// Remove a subscriber
func (e *ReactorEvent) Remove(ch chan React) {
    e.mut.Lock()
    defer e.mut.Unlock()

    for i, c := range e.chans {
        if c == ch {
            e.chans = append(e.chans[:i], e.chans[i+1:]...)
        }
    }
}

// Basic reactor resource
type React struct {
    Resource interface{}
    Event    string
}

// The reactor basic engine. Acts as bridge
// between the events and the subscribers/posters
type ReactorEngine struct {
    patterns map[string]*ReactorEvent
}

func NewReactorEngine() *ReactorEngine {
    return &ReactorEngine{patterns: make(map[string]*ReactorEvent)}
}

// Subscribe a channel to the specified event
func (reactor *ReactorEngine) Subscribe(event string, ch chan React) {
    ev := reactor.patterns[event]
    // Create a new event if one isn't available
    if ev == nil {
        ev = &ReactorEvent{event: event}
        reactor.patterns[event] = ev
    }

    // Add the channel to reactor event handler
    ev.Add(ch)
}

func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) {
    ev := reactor.patterns[event]
    if ev != nil {
        ev.Remove(ch)
    }
}

func (reactor *ReactorEngine) Post(event string, resource interface{}) {
    ev := reactor.patterns[event]
    if ev != nil {
        ev.Post(React{Resource: resource, Event: event})
    }
}