63 lines
1.6 KiB
Go
Raw Normal View History

2022-02-06 07:06:32 +00:00
// Copyright (C) 2017 Michael J. Fromberger. All Rights Reserved.
2021-12-04 16:42:11 +00:00
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() }