Skip to content

Commit 0aae9fd

Browse files
committed
Lots of work around packets and binary data.
1 parent cbd3979 commit 0aae9fd

14 files changed

Lines changed: 447 additions & 142 deletions

File tree

‎go.mod‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/ergo-services/ergo v1.999.201
77
github.com/geomyidia/zylog v0.1.5
88
github.com/google/uuid v1.3.0
9-
github.com/okeuday/erlang_go/v2 v2.0.2
9+
github.com/okeuday/erlang_go/v2 v2.0.5
1010
github.com/sirupsen/logrus v1.8.1
1111
github.com/stretchr/testify v1.5.1
1212
gitlab.com/gomidi/midi v1.23.7

‎go.sum‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
2525
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
2626
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
2727
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
28-
github.com/okeuday/erlang_go/v2 v2.0.2 h1:FgdZ/xxEpYNMsoGwpYsy2AecKyMPadlfq0+epT9gpSk=
29-
github.com/okeuday/erlang_go/v2 v2.0.2/go.mod h1:bUnKKmkI110+DM1rV59zPPqbcXp4yv18Fp2ofRwBmk4=
28+
github.com/okeuday/erlang_go/v2 v2.0.5 h1:GLv90a/7KhQlDUngcgLyNhP3IbmKnFvA0p2Rq/nLoKc=
29+
github.com/okeuday/erlang_go/v2 v2.0.5/go.mod h1:bUnKKmkI110+DM1rV59zPPqbcXp4yv18Fp2ofRwBmk4=
3030
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3131
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
3232
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=

‎pkg/erl/datatypes/datatypes.go‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,28 @@ package datatypes
33
import (
44
"github.com/okeuday/erlang_go/v2/erlang"
55
log "github.com/sirupsen/logrus"
6+
7+
"github.com/ut-proj/midiserver/pkg/erl/packets"
68
)
79

10+
func FromPacket(pkt *packets.Packet) (interface{}, error) {
11+
bytes, err := pkt.Bytes()
12+
if err != nil {
13+
log.Error(err)
14+
return nil, err
15+
}
16+
return FromBytes(bytes)
17+
}
18+
19+
func FromBytes(data []byte) (interface{}, error) {
20+
term, err := erlang.BinaryToTerm(data)
21+
if err != nil {
22+
log.Error(err)
23+
return nil, err
24+
}
25+
return FromTerm(term)
26+
}
27+
828
func FromTerm(term interface{}) (interface{}, error) {
929
log.Tracef("Processing term: %+v", term)
1030
switch t := term.(type) {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package datatypes
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/suite"
7+
8+
"github.com/ut-proj/midiserver/pkg/erl"
9+
"github.com/ut-proj/midiserver/pkg/erl/packets"
10+
"github.com/ut-proj/midiserver/pkg/erl/testdata"
11+
)
12+
13+
type FromPacketTestSuite struct {
14+
suite.Suite
15+
opts *erl.Opts
16+
}
17+
18+
func (s *FromPacketTestSuite) SetupSuite() {
19+
s.opts = &erl.Opts{IsHexEncoded: true}
20+
}
21+
22+
func (s *FromPacketTestSuite) TestNew() {
23+
pkt, err := packets.NewPacket(testdata.BatchPacketBytes, s.opts)
24+
s.NoError(err)
25+
t, err := FromPacket(pkt)
26+
s.NoError(err)
27+
s.Equal("midi", t.(*Tuple).Elements()[0].(*Atom).Value())
28+
s.Equal("batch", t.(*Tuple).Elements()[1].(*Tuple).Elements()[0].(*Atom).Value())
29+
30+
pkt, err = packets.NewPacket(testdata.DevicePacketBytes, s.opts)
31+
s.NoError(err)
32+
t, err = FromPacket(pkt)
33+
s.NoError(err)
34+
s.Equal("midi", t.(*Tuple).Elements()[0].(*Atom).Value())
35+
s.Equal("batch", t.(*Tuple).Elements()[1].(*Tuple).Elements()[0].(*Atom).Value())
36+
37+
pkt, err = packets.NewPacket(testdata.NoteOnPacketBytes, s.opts)
38+
s.NoError(err)
39+
t, err = FromPacket(pkt)
40+
s.NoError(err)
41+
s.Equal("midi", t.(*Tuple).Elements()[0].(*Atom).Value())
42+
s.Equal("batch", t.(*Tuple).Elements()[1].(*Tuple).Elements()[0].(*Atom).Value())
43+
}
44+
45+
func TestFromPacketTestSuite(t *testing.T) {
46+
suite.Run(t, new(FromPacketTestSuite))
47+
}
48+
49+
type FromBytesTestSuite struct {
50+
suite.Suite
51+
}
52+
53+
func (s *FromBytesTestSuite) SetupSuite() {
54+
}
55+
56+
func (s *FromBytesTestSuite) TestNewFromBytes() {
57+
t, err := FromBytes(testdata.BatchETFBytes)
58+
s.NoError(err)
59+
msg := t.(*Tuple).Elements()
60+
msgType := msg[0].(*Atom).Value()
61+
msgPayload := msg[1].(*Tuple).Elements()
62+
msgPayloadType := msgPayload[0].(*Atom).Value()
63+
s.Equal("midi", msgType)
64+
s.Equal("batch", msgPayloadType)
65+
66+
t, err = FromBytes(testdata.DeviceETFBytes)
67+
s.NoError(err)
68+
msg = t.(*Tuple).Elements()
69+
msgType = msg[0].(*Atom).Value()
70+
msgPayload = msg[1].(*Tuple).Elements()
71+
msgPayloadType = msgPayload[0].(*Atom).Value()
72+
s.Equal("midi", msgType)
73+
s.Equal("batch", msgPayloadType)
74+
75+
t, err = FromBytes(testdata.NoteOnETFBytes)
76+
s.NoError(err)
77+
msg = t.(*Tuple).Elements()
78+
msgType = msg[0].(*Atom).Value()
79+
msgPayload = msg[1].(*Tuple).Elements()
80+
msgPayloadType = msgPayload[0].(*Atom).Value()
81+
s.Equal("midi", msgType)
82+
s.Equal("batch", msgPayloadType)
83+
}
84+
85+
func TestFromBytesTestSuite(t *testing.T) {
86+
suite.Run(t, new(FromBytesTestSuite))
87+
}

‎pkg/erl/messages/errors.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ var (
77
ErrMsgNameFormat = errors.New("incorrect message name format (needs to be atom)")
88
ErrMsgTupleFormat = errors.New("incorrect message format (message needs to be tuple)")
99
ErrMsgAtomFormat = errors.New("incorrect message format (command needs to be atom)")
10-
ErrMsgValueFormat = errors.New("message value in unsupported format (needs to be atom or list)")
10+
ErrMsgValueFormat = errors.New("message value in unsupported format (needs to be atom , list, or tuple)")
1111
)

‎pkg/erl/messages/message.go‎

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,29 @@ type Message struct {
1212
args *datatypes.List
1313
}
1414

15-
func New(term interface{}) (*Message, error) {
16-
var ok bool
17-
var msgTuple *datatypes.Tuple
15+
func NewFromBytes(data []byte) (*Message, error) {
16+
t, err := datatypes.FromBytes(data)
17+
if err != nil {
18+
log.Error(err)
19+
return nil, err
20+
}
21+
return New(t)
22+
}
23+
24+
func NewFromTerm(term interface{}) (*Message, error) {
1825
t, err := datatypes.FromTerm(term)
1926
if err != nil {
2027
log.Error(err)
2128
return nil, err
2229
}
23-
log.Tracef("Got Go/Erlang ports data: %+v", t)
24-
parts, ok := t.(*datatypes.List)
25-
if ok {
26-
if parts.Len() > 2 {
27-
log.Error(ErrMsgListFormat)
28-
return nil, ErrMsgListFormat
29-
}
30-
msgTuple, ok = parts.Nth(0).(*datatypes.Tuple)
31-
if !ok {
32-
log.Error(ErrMsgTupleFormat)
33-
return nil, ErrMsgTupleFormat
34-
}
35-
} else {
36-
msgTuple, ok = t.(*datatypes.Tuple)
37-
if !ok {
38-
log.Error(ErrMsgTupleFormat)
39-
return nil, ErrMsgTupleFormat
40-
}
30+
return New(t)
31+
}
32+
33+
func New(t interface{}) (*Message, error) {
34+
var ok bool
35+
msgTuple, err := messageTuple(t)
36+
if err != nil {
37+
return nil, err
4138
}
4239
log.Debugf("Got message tuple: %+v", msgTuple)
4340
msgType, ok := msgTuple.Key().(*datatypes.Atom)
@@ -47,28 +44,17 @@ func New(term interface{}) (*Message, error) {
4744
}
4845
log.Debugf("Got message type %v", msgType)
4946

50-
var name *datatypes.Atom
5147
args := datatypes.NewList([]interface{}{})
52-
name, ok = msgTuple.Value().(*datatypes.Atom)
48+
name, ok := msgTuple.Value().(*datatypes.Atom)
5349
if ok {
50+
// This is the case for a simple message with just a name and no args
5451
log.Debugf("Got message name %s", name)
5552
} else {
56-
msgData, ok := msgTuple.Value().(*datatypes.List)
57-
if !ok {
58-
log.Error(ErrMsgValueFormat)
59-
return nil, ErrMsgValueFormat
60-
}
61-
if len(msgData.Elements()) == 0 {
62-
log.Error(ErrMsgValueFormat)
63-
return nil, ErrMsgValueFormat
64-
}
65-
name, ok = msgData.Elements()[0].(*datatypes.Atom)
66-
if !ok {
67-
log.Error(ErrMsgNameFormat)
68-
return nil, ErrMsgNameFormat
53+
// This is the case for more highly-structured messages
54+
name, args, err = messageNameArgs(msgTuple)
55+
if err != nil {
56+
return nil, err
6957
}
70-
log.Debugf("Got message name %s", name)
71-
args = datatypes.NewList(msgData.Elements()[1:])
7258
}
7359
// If this is a MIDI message
7460
return &Message{
@@ -98,3 +84,57 @@ func (m *Message) Args() []interface{} {
9884
}
9985

10086
// Private functions
87+
88+
func messageTuple(t interface{}) (*datatypes.Tuple, error) {
89+
var msgTuple *datatypes.Tuple
90+
log.Tracef("Got Go/Erlang ports data: %+v", t)
91+
parts, ok := t.(*datatypes.List)
92+
if ok {
93+
if parts.Len() > 2 {
94+
log.Error(ErrMsgListFormat)
95+
return nil, ErrMsgListFormat
96+
}
97+
msgTuple, ok = parts.Nth(0).(*datatypes.Tuple)
98+
if !ok {
99+
log.Error(ErrMsgTupleFormat)
100+
return nil, ErrMsgTupleFormat
101+
}
102+
} else {
103+
msgTuple, ok = t.(*datatypes.Tuple)
104+
if !ok {
105+
log.Error(ErrMsgTupleFormat)
106+
return nil, ErrMsgTupleFormat
107+
}
108+
}
109+
return msgTuple, nil
110+
}
111+
112+
func messageNameArgs(msgTuple *datatypes.Tuple) (*datatypes.Atom, *datatypes.List, error) {
113+
var msgData []interface{}
114+
var name *datatypes.Atom
115+
var ok bool
116+
msgVal := msgTuple.Value()
117+
x, ok := msgVal.(*datatypes.List)
118+
if ok {
119+
msgData = x.Elements()
120+
} else {
121+
x, ok := msgVal.(*datatypes.Tuple)
122+
if !ok {
123+
log.Error(ErrMsgValueFormat)
124+
return nil, nil, ErrMsgValueFormat
125+
}
126+
msgData = x.Elements()
127+
}
128+
if len(msgData) == 0 {
129+
log.Error(ErrMsgValueFormat)
130+
return nil, nil, ErrMsgValueFormat
131+
}
132+
name, ok = msgData[0].(*datatypes.Atom)
133+
if !ok {
134+
log.Error(ErrMsgNameFormat)
135+
return nil, nil, ErrMsgNameFormat
136+
}
137+
log.Debugf("Got message name %s", name)
138+
args := datatypes.NewList(msgData[1:])
139+
return name, args, nil
140+
}

‎pkg/erl/messages/message_test.go‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package messages
2+
3+
import (
4+
"sort"
5+
"testing"
6+
7+
"github.com/google/uuid"
8+
"github.com/stretchr/testify/suite"
9+
10+
"github.com/ut-proj/midiserver/pkg/erl/datatypes"
11+
"github.com/ut-proj/midiserver/pkg/erl/testdata"
12+
)
13+
14+
type MessageTestSuite struct {
15+
suite.Suite
16+
}
17+
18+
func (s *MessageTestSuite) SetupSuite() {
19+
}
20+
21+
func (s *MessageTestSuite) TestNewFromBytesBatch() {
22+
msg, err := NewFromBytes(testdata.BatchETFBytes)
23+
s.NoError(err)
24+
s.Equal("midi", msg.Type())
25+
s.Equal("batch", msg.Name())
26+
args := msg.Args()
27+
s.Equal(1, len(args))
28+
batches := args[0].(*datatypes.List).Elements()
29+
batch1 := batches[0].(*datatypes.Tuple).Elements()
30+
s.Equal("id", batch1[0].(*datatypes.Atom).Value())
31+
id, err := uuid.FromBytes(batch1[1].(*datatypes.Binary).Value())
32+
s.NoError(err)
33+
s.Equal("30969579-ca53-4ba0-b4af-acfced709864", id.String())
34+
batch2 := batches[1].(*datatypes.Tuple).Elements()
35+
s.Equal("messages", batch2[0].(*datatypes.Atom).Value())
36+
msgs := batch2[1].(*datatypes.List).Elements()
37+
s.Equal(4, len(msgs))
38+
var msgNames []string
39+
for _, msg := range msgs {
40+
msgNames = append(msgNames, msg.(*datatypes.Tuple).Key().(*datatypes.Atom).Value())
41+
}
42+
sort.Strings(msgNames)
43+
s.Equal([]string{"channel", "device", "note_off", "note_on"}, msgNames)
44+
}
45+
46+
func TestMessageTestSuite(t *testing.T) {
47+
suite.Run(t, new(MessageTestSuite))
48+
}

0 commit comments

Comments
 (0)