Renamed triggers to handlers
This commit is contained in:
@@ -59,7 +59,7 @@ type (
|
||||
}
|
||||
|
||||
eventRegistry interface {
|
||||
Register(h eventbus.Handler, ops ...eventbus.TriggerRegOp) uintptr
|
||||
Register(h eventbus.HandlerFn, ops ...eventbus.HandlerRegOp) uintptr
|
||||
Unregister(ptrs ...uintptr)
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ func (svc *service) registerServerScripts(ss ...*ServerScript) {
|
||||
// registers that script to the list of manual triggers
|
||||
func (svc *service) registerTriggers(script *ServerScript) []uintptr {
|
||||
var (
|
||||
ops []eventbus.TriggerRegOp
|
||||
ops []eventbus.HandlerRegOp
|
||||
err error
|
||||
ptrs = make([]uintptr, 0, len(script.Triggers))
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ func pluckManualTriggers(script *ServerScript) map[string]string {
|
||||
}
|
||||
|
||||
// converts trigger's constraint to eventbus' constraint options
|
||||
func makeTriggerOpts(t *Trigger) (oo []eventbus.TriggerRegOp, err error) {
|
||||
func makeTriggerOpts(t *Trigger) (oo []eventbus.HandlerRegOp, err error) {
|
||||
if len(t.Events) == 0 {
|
||||
return nil, fmt.Errorf("can not generate trigger without at least one events")
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func TestTriggerOptsMaking(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
oo []eventbus.TriggerRegOp
|
||||
oo []eventbus.HandlerRegOp
|
||||
err error
|
||||
)
|
||||
|
||||
|
||||
+10
-10
@@ -1,6 +1,6 @@
|
||||
# pkg/eventbus
|
||||
|
||||
Package handles event dispatching and trigger registration
|
||||
Package handles event dispatching and handler registration
|
||||
|
||||
## Event
|
||||
|
||||
@@ -21,14 +21,14 @@ Deferred events (onTimestamp and onInterval) are executed by scheduler package s
|
||||
#### Manual events
|
||||
|
||||
Manual events (onManual) are a special case.
|
||||
Events are not (nor should be) triggered directly or through eventbus.
|
||||
These events are not (nor should be) dispatched directly or through event-bus.
|
||||
|
||||
We use it to route requests and pack attributes from the API to the Corredor service
|
||||
|
||||
### Event matcher
|
||||
|
||||
Matcher is a function on event that helps filtering fired events.
|
||||
It decides (returns true or false) if fired event is a match for any of a registered triggers
|
||||
It decides (returns true or false) if fired event is a match for any of a registered handlers
|
||||
|
||||
Bus has basic internal filtering for resource & event type.
|
||||
Other constraints are passed to event's matcher function.
|
||||
@@ -45,20 +45,20 @@ All constraints must match.
|
||||
First non-match will break constraint checking procedure.
|
||||
|
||||
|
||||
## Triggers
|
||||
## Handler
|
||||
|
||||
Trigger is combination of (event matching) rules/constraints and event handler.
|
||||
Handler is a callback function called when a compatible event is fired.
|
||||
Handler is combination of (event matching) rules/constraints and handler callback function.
|
||||
Function is called when a event compatible with registered rules & constraints is fired.
|
||||
|
||||
Trigger can respond to multiple resource/event combinations.
|
||||
Handler can respond to multiple resource/event combinations.
|
||||
|
||||
### Constraints
|
||||
|
||||
Matcher function is called multiple times, once per each trigger constraint.
|
||||
Matcher function is called multiple times, once per each handler constraint.
|
||||
If any of the calls result in a non-match, check
|
||||
|
||||
Trigger without constraint is considered a match.
|
||||
Handler without any constraints is considered a match.
|
||||
|
||||
### Weight
|
||||
|
||||
Weight controls order of trigger execution.
|
||||
Weight controls order of execution.
|
||||
|
||||
@@ -112,11 +112,11 @@ func mustLikeMaker(name string, not bool, vv ...string) (*mustBeLike, error) {
|
||||
}
|
||||
|
||||
func MustBeLike(name string, vv ...string) (ConstraintMatcher, error) {
|
||||
return &mustBeLike{name: name, values: vv}, nil
|
||||
return mustLikeMaker(name, false, vv...)
|
||||
}
|
||||
|
||||
func MustNotBeLike(name string, vv ...string) (ConstraintMatcher, error) {
|
||||
return &mustBeLike{name: name, values: vv, not: true}, nil
|
||||
return mustLikeMaker(name, true, vv...)
|
||||
}
|
||||
|
||||
func (c mustBeLike) Match(value string) bool {
|
||||
|
||||
+18
-18
@@ -24,11 +24,11 @@ type (
|
||||
wg *sync.WaitGroup
|
||||
|
||||
// Read & write locking
|
||||
// prevent event handling during trigger (un)registration
|
||||
// prevent event handling during handler (un)registration
|
||||
l *sync.RWMutex
|
||||
|
||||
// list of registered handlers
|
||||
triggers map[uintptr]*trigger
|
||||
handlers map[uintptr]*handler
|
||||
}
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ func New() *eventbus {
|
||||
return &eventbus{
|
||||
wg: &sync.WaitGroup{},
|
||||
l: &sync.RWMutex{},
|
||||
triggers: make(map[uintptr]*trigger),
|
||||
handlers: make(map[uintptr]*handler),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func (b *eventbus) WaitFor(ctx context.Context, ev Event) (err error) {
|
||||
b.l.RLock()
|
||||
defer b.l.RUnlock()
|
||||
for _, t := range b.find(ev) {
|
||||
err = func(ctx context.Context, t *trigger) error {
|
||||
err = func(ctx context.Context, t *handler) error {
|
||||
b.wg.Add(1)
|
||||
defer b.wg.Done()
|
||||
return t.Handle(ctx, ev)
|
||||
@@ -82,7 +82,7 @@ func (b *eventbus) Dispatch(ctx context.Context, ev Event) {
|
||||
defer b.l.RUnlock()
|
||||
for _, t := range b.find(ev) {
|
||||
b.wg.Add(1)
|
||||
go func(ctx context.Context, t *trigger) {
|
||||
go func(ctx context.Context, t *handler) {
|
||||
defer b.wg.Done()
|
||||
_ = t.Handle(ctx, ev)
|
||||
}(ctx, t)
|
||||
@@ -96,18 +96,18 @@ func (b *eventbus) wait() {
|
||||
b.wg.Wait()
|
||||
}
|
||||
|
||||
// Finds all registered triggers compatible with given event
|
||||
// Finds all registered handlers compatible with given event
|
||||
//
|
||||
// It returns sorted triggers
|
||||
// It returns sorted handlers
|
||||
//
|
||||
// There is still room for improvement (performance wise) by indexing
|
||||
// resources and events of each trigger.
|
||||
func (b *eventbus) find(ev Event) (tt TriggerSet) {
|
||||
// resources and events of each handler.
|
||||
func (b *eventbus) find(ev Event) (tt HandlerSet) {
|
||||
if ev == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range b.triggers {
|
||||
for _, t := range b.handlers {
|
||||
|
||||
if !t.Match(ev) {
|
||||
continue
|
||||
@@ -121,28 +121,28 @@ func (b *eventbus) find(ev Event) (tt TriggerSet) {
|
||||
return
|
||||
}
|
||||
|
||||
// Register creates a new trigger with given handler, resource, event with other options and constraints
|
||||
// Register creates a new handler with given handler, resource, event with other options and constraints
|
||||
//
|
||||
// It returns a trigger identifier that can be used to remove (unregister) trigger later
|
||||
func (b *eventbus) Register(h Handler, ops ...TriggerRegOp) uintptr {
|
||||
// It returns a handler identifier that can be used to remove (unregister) handler later
|
||||
func (b *eventbus) Register(h HandlerFn, ops ...HandlerRegOp) uintptr {
|
||||
b.l.Lock()
|
||||
defer b.l.Unlock()
|
||||
|
||||
var (
|
||||
trigger = NewTrigger(h, ops...)
|
||||
ptr = uintptr(unsafe.Pointer(trigger))
|
||||
handlers = NewHandler(h, ops...)
|
||||
ptr = uintptr(unsafe.Pointer(handlers))
|
||||
)
|
||||
|
||||
b.triggers[ptr] = trigger
|
||||
b.handlers[ptr] = handlers
|
||||
return ptr
|
||||
}
|
||||
|
||||
// Unregister removes one or more registered triggers
|
||||
// Unregister removes one or more registered handlers
|
||||
func (b *eventbus) Unregister(ptrs ...uintptr) {
|
||||
b.l.Lock()
|
||||
defer b.l.Unlock()
|
||||
|
||||
for _, ptr := range ptrs {
|
||||
delete(b.triggers, ptr)
|
||||
delete(b.handlers, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,23 +18,23 @@ func TestEventbusRegUnreg(t *testing.T) {
|
||||
bus = New()
|
||||
)
|
||||
|
||||
a.Empty(bus.triggers)
|
||||
a.Empty(bus.handlers)
|
||||
h1 := bus.Register(nil)
|
||||
a.NotZero(h1)
|
||||
h2 := bus.Register(nil)
|
||||
a.NotZero(h2)
|
||||
h3 := bus.Register(nil)
|
||||
a.NotZero(h3)
|
||||
a.Len(bus.triggers, 3)
|
||||
a.Len(bus.handlers, 3)
|
||||
bus.Unregister(h1)
|
||||
a.Len(bus.triggers, 2)
|
||||
a.Len(bus.handlers, 2)
|
||||
bus.Unregister(h2)
|
||||
a.Len(bus.triggers, 1)
|
||||
a.Len(bus.handlers, 1)
|
||||
bus.Unregister(h3)
|
||||
a.Empty(bus.triggers)
|
||||
a.Empty(bus.handlers)
|
||||
}
|
||||
|
||||
func BenchmarkEventbusTriggerLookup(b *testing.B) {
|
||||
func BenchmarkEventbusHandlerLookup(b *testing.B) {
|
||||
var (
|
||||
bus = New()
|
||||
ptrs []uintptr
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
Handler func(ctx context.Context, ev Event) error
|
||||
HandlerFn func(ctx context.Context, ev Event) error
|
||||
|
||||
trigger struct {
|
||||
handler Handler
|
||||
handler struct {
|
||||
handler HandlerFn
|
||||
resourceTypes map[string]bool
|
||||
eventTypes map[string]bool
|
||||
constraints constraintSet
|
||||
@@ -19,30 +19,30 @@ type (
|
||||
}
|
||||
|
||||
// @todo add sorting interface
|
||||
TriggerSet []*trigger
|
||||
HandlerSet []*handler
|
||||
|
||||
TriggerRegOp func(t *trigger)
|
||||
HandlerRegOp func(t *handler)
|
||||
|
||||
eventInvokerSettable interface {
|
||||
SetInvoker(auth.Identifiable)
|
||||
}
|
||||
)
|
||||
|
||||
// Match matches trigger with resource event
|
||||
func (t trigger) Match(re Event) bool {
|
||||
// Match matches handler with resource event
|
||||
func (t handler) Match(re Event) bool {
|
||||
if re == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(re.ResourceType()) == 0 || !t.resourceTypes[re.ResourceType()] {
|
||||
// Expecting to have valid resource type and match at least one
|
||||
// defined resource on the trigger
|
||||
// defined resource on the handler
|
||||
return false
|
||||
}
|
||||
|
||||
if len(re.EventType()) == 0 || !t.eventTypes[re.EventType()] {
|
||||
// Expecting to have valid event type and match at least one
|
||||
// defined event on the trigger
|
||||
// defined event on the handler
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func (t trigger) Match(re Event) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (t trigger) Handle(ctx context.Context, ev Event) error {
|
||||
func (t handler) Handle(ctx context.Context, ev Event) error {
|
||||
defer sentry.Recover()
|
||||
|
||||
if eis, ok := ev.(eventInvokerSettable); ok {
|
||||
@@ -66,8 +66,8 @@ func (t trigger) Handle(ctx context.Context, ev Event) error {
|
||||
return t.handler(ctx, ev)
|
||||
}
|
||||
|
||||
func NewTrigger(h Handler, ops ...TriggerRegOp) *trigger {
|
||||
var t = &trigger{
|
||||
func NewHandler(h HandlerFn, ops ...HandlerRegOp) *handler {
|
||||
var t = &handler{
|
||||
resourceTypes: make(map[string]bool),
|
||||
eventTypes: make(map[string]bool),
|
||||
handler: h,
|
||||
@@ -80,36 +80,36 @@ func NewTrigger(h Handler, ops ...TriggerRegOp) *trigger {
|
||||
return t
|
||||
}
|
||||
|
||||
func For(rr ...string) TriggerRegOp {
|
||||
return func(t *trigger) {
|
||||
func For(rr ...string) HandlerRegOp {
|
||||
return func(t *handler) {
|
||||
for _, r := range rr {
|
||||
t.resourceTypes[r] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func On(ee ...string) TriggerRegOp {
|
||||
return func(t *trigger) {
|
||||
func On(ee ...string) HandlerRegOp {
|
||||
return func(t *handler) {
|
||||
for _, e := range ee {
|
||||
t.eventTypes[e] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Constraint(c ConstraintMatcher) TriggerRegOp {
|
||||
return func(t *trigger) {
|
||||
func Constraint(c ConstraintMatcher) HandlerRegOp {
|
||||
return func(t *handler) {
|
||||
t.constraints = append(t.constraints, c)
|
||||
}
|
||||
}
|
||||
|
||||
func Weight(weight int) TriggerRegOp {
|
||||
return func(t *trigger) {
|
||||
func Weight(weight int) HandlerRegOp {
|
||||
return func(t *handler) {
|
||||
t.weight = weight
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger-set sorting:
|
||||
// handler sorting:
|
||||
|
||||
func (set TriggerSet) Len() int { return len(set) }
|
||||
func (set TriggerSet) Swap(i, j int) { set[i], set[j] = set[j], set[i] }
|
||||
func (set TriggerSet) Less(i, j int) bool { return set[i].weight < set[j].weight }
|
||||
func (set HandlerSet) Len() int { return len(set) }
|
||||
func (set HandlerSet) Swap(i, j int) { set[i], set[j] = set[j], set[i] }
|
||||
func (set HandlerSet) Less(i, j int) bool { return set[i].weight < set[j].weight }
|
||||
@@ -41,10 +41,10 @@ func (e *mockEvent) SetInvoker(identity auth.Identifiable) {
|
||||
e.identity = identity
|
||||
}
|
||||
|
||||
func TestTrigger_Match(t *testing.T) {
|
||||
func TestHandler_Match(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
ops []TriggerRegOp
|
||||
ops []HandlerRegOp
|
||||
ev Event
|
||||
match bool
|
||||
}{
|
||||
@@ -54,22 +54,22 @@ func TestTrigger_Match(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{"empty resource",
|
||||
[]TriggerRegOp{For("foo"), On("bar")},
|
||||
[]HandlerRegOp{For("foo"), On("bar")},
|
||||
&mockEvent{rType: "", eType: "bar"},
|
||||
false,
|
||||
},
|
||||
{"empty event",
|
||||
[]TriggerRegOp{For("foo"), On("bar")},
|
||||
[]HandlerRegOp{For("foo"), On("bar")},
|
||||
&mockEvent{rType: "foo", eType: ""},
|
||||
false,
|
||||
},
|
||||
{"simple foo-bar test",
|
||||
[]TriggerRegOp{For("foo"), On("bar")},
|
||||
[]HandlerRegOp{For("foo"), On("bar")},
|
||||
&mockEvent{rType: "foo", eType: "bar"},
|
||||
true,
|
||||
},
|
||||
{"ConstraintMatcher match",
|
||||
[]TriggerRegOp{For("foo"), On("bar"), Constraint(MustMakeConstraint("baz", "=", "baz"))},
|
||||
[]HandlerRegOp{For("foo"), On("bar"), Constraint(MustMakeConstraint("baz", "=", "baz"))},
|
||||
&mockEvent{
|
||||
rType: "foo",
|
||||
eType: "bar",
|
||||
@@ -79,7 +79,7 @@ func TestTrigger_Match(t *testing.T) {
|
||||
true,
|
||||
},
|
||||
{"ConstraintMatcher mismatch",
|
||||
[]TriggerRegOp{For("foo"), On("bar"), Constraint(MustMakeConstraint("baz", "=", "baz"))},
|
||||
[]HandlerRegOp{For("foo"), On("bar"), Constraint(MustMakeConstraint("baz", "=", "baz"))},
|
||||
&mockEvent{
|
||||
rType: "foo",
|
||||
eType: "bar",
|
||||
@@ -92,20 +92,20 @@ func TestTrigger_Match(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
var trigger = NewTrigger(nil, c.ops...)
|
||||
var handler = NewHandler(nil, c.ops...)
|
||||
if c.match {
|
||||
assert.True(t, trigger.Match(c.ev), "Expecting to match")
|
||||
assert.True(t, handler.Match(c.ev), "Expecting to match")
|
||||
|
||||
} else {
|
||||
assert.False(t, trigger.Match(c.ev), "Expecting to not match")
|
||||
assert.False(t, handler.Match(c.ev), "Expecting to not match")
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrigger_RegOps(t *testing.T) {
|
||||
makeTestTrigger := func(t *trigger) *trigger {
|
||||
func TestHandler_RegOps(t *testing.T) {
|
||||
makeTestHandler := func(t *handler) *handler {
|
||||
if t.resourceTypes == nil {
|
||||
t.resourceTypes = make(map[string]bool)
|
||||
}
|
||||
@@ -119,45 +119,45 @@ func TestTrigger_RegOps(t *testing.T) {
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
exp *trigger
|
||||
ops []TriggerRegOp
|
||||
exp *handler
|
||||
ops []HandlerRegOp
|
||||
}{
|
||||
{
|
||||
"empty",
|
||||
makeTestTrigger(&trigger{}),
|
||||
makeTestHandler(&handler{}),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"resource types",
|
||||
makeTestTrigger(&trigger{resourceTypes: map[string]bool{"foo": true, "bar": true}}),
|
||||
[]TriggerRegOp{For("foo", "bar")},
|
||||
makeTestHandler(&handler{resourceTypes: map[string]bool{"foo": true, "bar": true}}),
|
||||
[]HandlerRegOp{For("foo", "bar")},
|
||||
},
|
||||
{
|
||||
"event types",
|
||||
makeTestTrigger(&trigger{eventTypes: map[string]bool{"foo": true, "bar": true}}),
|
||||
[]TriggerRegOp{On("foo", "bar")},
|
||||
makeTestHandler(&handler{eventTypes: map[string]bool{"foo": true, "bar": true}}),
|
||||
[]HandlerRegOp{On("foo", "bar")},
|
||||
},
|
||||
{
|
||||
"weight",
|
||||
makeTestTrigger(&trigger{weight: 42}),
|
||||
[]TriggerRegOp{Weight(42)},
|
||||
makeTestHandler(&handler{weight: 42}),
|
||||
[]HandlerRegOp{Weight(42)},
|
||||
},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
assert.Equal(t, c.exp, NewTrigger(nil, c.ops...))
|
||||
assert.Equal(t, c.exp, NewHandler(nil, c.ops...))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTriggerHandler(t *testing.T) {
|
||||
func TestHandlerHandler(t *testing.T) {
|
||||
var (
|
||||
a = assert.New(t)
|
||||
ctx = context.Background()
|
||||
ev = &mockEvent{}
|
||||
passedthrough bool
|
||||
|
||||
trSimple = &trigger{
|
||||
trSimple = &handler{
|
||||
handler: func(ctx context.Context, ev Event) error {
|
||||
passedthrough = true
|
||||
a.True(auth.IsSuperUser(ev.(*mockEvent).identity))
|
||||
@@ -175,16 +175,16 @@ func TestTriggerHandler(t *testing.T) {
|
||||
a.True(passedthrough, "expecting to pass through simple handler")
|
||||
}
|
||||
|
||||
func TestTriggerSorting(t *testing.T) {
|
||||
func TestHandlerSorting(t *testing.T) {
|
||||
var (
|
||||
a = assert.New(t)
|
||||
tt = TriggerSet{
|
||||
NewTrigger(nil, Weight(3)),
|
||||
NewTrigger(nil, Weight(1)),
|
||||
NewTrigger(nil, Weight(2)),
|
||||
tt = HandlerSet{
|
||||
NewHandler(nil, Weight(3)),
|
||||
NewHandler(nil, Weight(1)),
|
||||
NewHandler(nil, Weight(2)),
|
||||
}
|
||||
|
||||
w2s = func(tt TriggerSet) (out string) {
|
||||
w2s = func(tt HandlerSet) (out string) {
|
||||
for _, t := range tt {
|
||||
out += fmt.Sprintf("%d,", t.weight)
|
||||
}
|
||||
Reference in New Issue
Block a user