/
mllp.go
98 lines (77 loc) · 1.79 KB
/
mllp.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
91
92
93
94
95
96
97
98
package mllp
import (
"bufio"
"io"
"github.com/facebookgo/stackerr"
)
type ErrInvalidHeader error
type ErrInvalidContent error
type ErrInvalidBoundary error
type ErrInvalidTrailer error
func NewReader(r io.Reader) *Reader {
return &Reader{
b: bufio.NewReader(r),
}
}
type Reader struct {
b *bufio.Reader
}
func (r Reader) ReadMessage() ([]byte, error) {
c, err := r.b.ReadByte()
if err != nil {
return nil, stackerr.Wrap(err)
}
if c != byte(0x0b) {
return nil, ErrInvalidHeader(stackerr.Newf("invalid header found; expected 0x0b but got %02x", c))
}
d, err := r.b.ReadBytes(byte(0x1c))
if err != nil {
return nil, stackerr.Wrap(err)
}
if len(d) < 2 {
return nil, ErrInvalidContent(stackerr.Newf("content including boundary should be at least two bytes long; instead was %d", len(d)))
}
if d[len(d)-2] != 0x0d {
return nil, ErrInvalidBoundary(stackerr.Newf("content should end with 0x0d; instead was %02x", d[len(d)-2]))
}
t, err := r.b.ReadByte()
if err != nil {
return nil, stackerr.Wrap(err)
}
if t != byte(0x0d) {
return nil, ErrInvalidTrailer(stackerr.Newf("invalid trailer found; expected 0x0d but got %02x", t))
}
return d[0 : len(d)-2], nil
}
func NewWriter(w io.Writer) *Writer {
return &Writer{w: w}
}
type Writer struct {
w io.Writer
}
func (w Writer) WriteMessage(b []byte) error {
if _, err := w.w.Write([]byte{0x0b}); err != nil {
return stackerr.Wrap(err)
}
for len(b) > 0 {
n, err := w.w.Write(b)
if err != nil {
return stackerr.Wrap(err)
}
b = b[n:]
}
if _, err := w.w.Write([]byte{0x0d, 0x1c, 0x0d}); err != nil {
return stackerr.Wrap(err)
}
return nil
}
func NewReadWriter(rw io.ReadWriter) *ReadWriter {
return &ReadWriter{
Reader: NewReader(rw),
Writer: NewWriter(rw),
}
}
type ReadWriter struct {
*Reader
*Writer
}