61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package channel
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
// Line is a framing discipline for messages terminated by a Unicode LF
|
|
// (10). This framing has the constraint that records may not contain LF.
|
|
var Line = Split('\n')
|
|
|
|
// Split returns a framing in which each message is terminated by the specified
|
|
// byte value. The framing has the constraint that outbound records may not
|
|
// contain the split byte internally.
|
|
func Split(b byte) Framing {
|
|
return func(r io.Reader, wc io.WriteCloser) Channel {
|
|
return split{split: b, wc: wc, buf: bufio.NewReader(r)}
|
|
}
|
|
}
|
|
|
|
// split implements Channel in which messages are terminated by occurrences of
|
|
// the specified byte. Outbound messages may not contain the split byte.
|
|
type split struct {
|
|
split byte
|
|
wc io.WriteCloser
|
|
buf *bufio.Reader
|
|
}
|
|
|
|
// Send implements part of the Channel interface. It reports an error if msg
|
|
// contains a split byte.
|
|
func (c split) Send(msg []byte) error {
|
|
if bytes.IndexByte(msg, c.split) >= 0 {
|
|
return errors.New("message contains split byte")
|
|
}
|
|
out := append(msg, c.split)
|
|
_, err := c.wc.Write(out)
|
|
return err
|
|
}
|
|
|
|
// Recv implements part of the Channel interface.
|
|
func (c split) Recv() ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
for {
|
|
chunk, err := c.buf.ReadSlice(c.split)
|
|
buf.Write(chunk)
|
|
if err == bufio.ErrBufferFull {
|
|
continue // incomplete line
|
|
}
|
|
line := buf.Bytes()
|
|
if n := len(line) - 1; n >= 0 {
|
|
return line[:n], err
|
|
}
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Close implements part of the Channel interface.
|
|
func (c split) Close() error { return c.wc.Close() }
|