| package logdriver // import "github.com/docker/docker/api/types/plugins/logdriver" |
| |
| import ( |
| "encoding/binary" |
| "io" |
| ) |
| |
| const binaryEncodeLen = 4 |
| |
| // LogEntryEncoder encodes a LogEntry to a protobuf stream |
| // The stream should look like: |
| // |
| // [uint32 binary encoded message size][protobuf message] |
| // |
| // To decode an entry, read the first 4 bytes to get the size of the entry, |
| // then read `size` bytes from the stream. |
| type LogEntryEncoder interface { |
| Encode(*LogEntry) error |
| } |
| |
| // NewLogEntryEncoder creates a protobuf stream encoder for log entries. |
| // This is used to write out log entries to a stream. |
| func NewLogEntryEncoder(w io.Writer) LogEntryEncoder { |
| return &logEntryEncoder{ |
| w: w, |
| buf: make([]byte, 1024), |
| } |
| } |
| |
| type logEntryEncoder struct { |
| buf []byte |
| w io.Writer |
| } |
| |
| func (e *logEntryEncoder) Encode(l *LogEntry) error { |
| n := l.Size() |
| |
| total := n + binaryEncodeLen |
| if total > len(e.buf) { |
| e.buf = make([]byte, total) |
| } |
| binary.BigEndian.PutUint32(e.buf, uint32(n)) |
| |
| if _, err := l.MarshalTo(e.buf[binaryEncodeLen:]); err != nil { |
| return err |
| } |
| _, err := e.w.Write(e.buf[:total]) |
| return err |
| } |
| |
| // LogEntryDecoder decodes log entries from a stream |
| // It is expected that the wire format is as defined by LogEntryEncoder. |
| type LogEntryDecoder interface { |
| Decode(*LogEntry) error |
| } |
| |
| // NewLogEntryDecoder creates a new stream decoder for log entries |
| func NewLogEntryDecoder(r io.Reader) LogEntryDecoder { |
| return &logEntryDecoder{ |
| lenBuf: make([]byte, binaryEncodeLen), |
| buf: make([]byte, 1024), |
| r: r, |
| } |
| } |
| |
| type logEntryDecoder struct { |
| r io.Reader |
| lenBuf []byte |
| buf []byte |
| } |
| |
| func (d *logEntryDecoder) Decode(l *LogEntry) error { |
| _, err := io.ReadFull(d.r, d.lenBuf) |
| if err != nil { |
| return err |
| } |
| |
| size := int(binary.BigEndian.Uint32(d.lenBuf)) |
| if len(d.buf) < size { |
| d.buf = make([]byte, size) |
| } |
| |
| if _, err := io.ReadFull(d.r, d.buf[:size]); err != nil { |
| return err |
| } |
| return l.Unmarshal(d.buf[:size]) |
| } |