-
Notifications
You must be signed in to change notification settings - Fork 9
/
dispatcher.go
90 lines (78 loc) · 2.08 KB
/
dispatcher.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
package osc
import (
"strings"
"time"
"github.com/pkg/errors"
)
// Common errors.
var (
ErrInvalidAddress = errors.New("invalid OSC address")
)
// Method is an OSC method
type Method func(msg Message) error
// Handle handles an OSC message.
func (method Method) Handle(m Message) error {
return method(m)
}
// MessageHandler is any type that can handle an OSC message.
type MessageHandler interface {
Handle(Message) error
}
// Dispatcher dispatches OSC packets.
type Dispatcher interface {
Dispatch(bundle Bundle, exactMatch bool) error
Invoke(msg Message, exactMatch bool) error
}
// PatternMatching is a dispatcher that implements OSC 1.0 pattern matching.
// See http://opensoundcontrol.org/spec-1_0 "OSC Message Dispatching and Pattern Matching"
type PatternMatching map[string]MessageHandler
// Dispatch invokes an OSC bundle's messages.
func (h PatternMatching) Dispatch(b Bundle, exactMatch bool) error {
var (
now = time.Now()
tt = b.Timetag.Time()
)
if tt.Before(now) {
return h.immediately(b, exactMatch)
}
<-time.After(tt.Sub(now))
return h.immediately(b, exactMatch)
}
// immediately invokes an OSC bundle immediately.
func (h PatternMatching) immediately(b Bundle, exactMatch bool) error {
for _, p := range b.Packets {
errs := []string{}
if err := h.invoke(p, exactMatch); err != nil {
errs = append(errs, err.Error())
}
if len(errs) > 0 {
return errors.New(strings.Join(errs, " and "))
}
return nil
}
return nil
}
// invoke invokes an OSC packet, which could be a message or a bundle of messages.
func (h PatternMatching) invoke(p Packet, exactMatch bool) error {
switch x := p.(type) {
case Message:
return h.Invoke(x, exactMatch)
case Bundle:
return h.immediately(x, exactMatch)
default:
return errors.Errorf("unsupported type for dispatcher: %T", p)
}
}
// Invoke invokes an OSC message.
func (h PatternMatching) Invoke(msg Message, exactMatch bool) error {
for address, handler := range h {
matched, err := msg.Match(address, exactMatch)
if err != nil {
return err
}
if matched {
return handler.Handle(msg)
}
}
return nil
}