This repository has been archived by the owner on Feb 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathserialdispatcher.go
87 lines (75 loc) · 1.76 KB
/
serialdispatcher.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
package command
import "sync"
// NewSerialDispatcher creates a new PrallelDispatcher with the given handlers
func NewSerialDispatcher(handlers []Handler) Dispatcher {
return &SerialDispatcher{
handlers: handlers,
mutex: sync.RWMutex{},
}
}
// SerialDispatcher is a command dispatcher wich will run all handlers in
// parallel and wait all handlers to finish before returning.
//
// If any handler returns an error the dispatcher will stop execution and will
// return that error.
//
// This dispatcher is *thread safe*.
type SerialDispatcher struct {
handlers []Handler
mutex sync.RWMutex
}
// AppendHandlers implements `Dispatcher.AppendHandlers`
func (d *SerialDispatcher) AppendHandlers(handlers ...Handler) {
d.mutex.Lock()
defer d.mutex.Unlock()
Loop:
for _, newHandler := range handlers {
for _, existingHandler := range d.handlers {
if newHandler == existingHandler {
continue Loop
}
}
d.handlers = append(d.handlers, newHandler)
}
}
// Dispatch implements `Dispatcher.Dispatch`
func (d *SerialDispatcher) Dispatch(cmd interface{}) (err error) {
d.mutex.RLock()
defer d.mutex.RUnlock()
defer func() {
if e := recover(); e != nil {
err = e.(error)
}
}()
found := false
for _, handler := range d.handlers {
if handler == nil {
continue
}
if !handler.CanHandle(cmd) {
continue
}
found = true
if err = handler.Handle(cmd, d); err != nil {
return
}
}
if !found {
return &NoHandlerFoundError{
Command: cmd,
}
}
return
}
// DispatchOptional implements `Dispatcher.DispatchOptional`
func (d *SerialDispatcher) DispatchOptional(cmd interface{}) (err error) {
d.mutex.RLock()
defer d.mutex.RUnlock()
err = d.Dispatch(cmd)
switch err.(type) {
case *NoHandlerFoundError:
return nil
default:
return err
}
}