package daemonconn import ( "encoding/binary" "io" ) type Typed interface { Type() uint32 } type Framed interface { Value() []byte } type Frame interface { Typed Framed } type frame struct { typeID uint32 valueBytes []byte } func (f frame) Type() uint32 { return f.typeID } func (f frame) Value() []byte { return f.valueBytes } // FrameReadWriter is a struct encapsulating io.ReadWriter, which provides additional methods for reading and // writing frames -- messages which have their own type and value byte buffer. // Data sent or received using this socket is expected to be encoded in LTV format, which means: // L - 4 bytes of frame length, big endian encoded // T - 4 bytes of frame type, big endian encoded // V - L bytes of frame data bytes type FrameReadWriter struct { io.ReadWriter } func (frw FrameReadWriter) ReadFrame() (Frame, error) { lengthBytes := make([]byte, 4) _, err := io.ReadFull(frw, lengthBytes) if err != nil { return nil, err } frameLength := binary.BigEndian.Uint32(lengthBytes) typeBytes := make([]byte, 4) _, err = io.ReadFull(frw, typeBytes) if err != nil { return nil, err } frameType := binary.LittleEndian.Uint32(typeBytes) frameBytes := make([]byte, frameLength) _, err = io.ReadFull(frw, frameBytes) if err != nil { return nil, err } result := frame{typeID: frameType, valueBytes: frameBytes} return result, nil } func (frw FrameReadWriter) WriteFrame(f Frame) error { frameLength := len(f.Value()) lengthBytes := make([]byte, 4) binary.BigEndian.PutUint32(lengthBytes, uint32(frameLength)) typeBytes := make([]byte, 4) binary.BigEndian.PutUint32(typeBytes, f.Type()) result := make([]byte, 0) result = append(result, lengthBytes...) result = append(result, typeBytes...) result = append(result, f.Value()...) _, err := frw.Write(result) if err != nil { return err } return nil }