package main import ( "bytes" "encoding/binary" "fmt" "io" "time" messages "git.tornberg.me/go-cart-actor/proto" "google.golang.org/protobuf/proto" ) type StorableMessage interface { Write(w io.Writer) error } type Message struct { Type uint16 TimeStamp *int64 Content interface{} } type MessageWriter struct { io.Writer } type StorableMessageHeader struct { Version uint16 Type uint16 TimeStamp int64 DataLength uint64 } func GetData(fn func(w io.Writer) error) ([]byte, error) { var buf bytes.Buffer err := fn(&buf) if err != nil { return nil, err } b := buf.Bytes() return b, nil } // func (w *MessageWriter) WriteUint64(value uint64) (int, error) { // bytes := make([]byte, 8) // binary.LittleEndian.PutUint64(bytes, value) // return w.Write(bytes) // } // func (w *MessageWriter) WriteInt64(value int64) (int, error) { // return w.WriteUint64(uint64(value)) // } // func (w *MessageWriter) WriteMessage(m *Message) (int, error) { // var i, l int // var err error // i, err = w.WriteUint64(m.Type) // l += i // i, err = w.WriteInt64(*m.TimeStamp) // l += i // var messageBytes []byte // var err error // if m.Type == AddRequestType { // messageBytes, err = proto.Marshal(m.Content.(*messages.AddRequest)) // } else if m.Type == AddItemType { // messageBytes, err = proto.Marshal(m.Content.(*messages.AddItem)) // } else { // return fmt.Errorf("unknown message type") // } // if err != nil { // return err // } // if err := w.WriteUint64(uint64(len(messageBytes))); err != nil { // return err // } // _, err = w.Write(messageBytes) // return err // } func (m Message) Write(w io.Writer) error { data, err := GetData(func(wr io.Writer) error { if m.Type == AddRequestType { messageBytes, err := proto.Marshal(m.Content.(*messages.AddRequest)) if err != nil { return err } wr.Write(messageBytes) } else if m.Type == AddItemType { messageBytes, err := proto.Marshal(m.Content.(*messages.AddItem)) if err != nil { return err } wr.Write(messageBytes) } return nil }) if err != nil { return err } ts := time.Now().Unix() if m.TimeStamp != nil { ts = *m.TimeStamp } err = binary.Write(w, binary.LittleEndian, StorableMessageHeader{ Version: 1, Type: m.Type, TimeStamp: ts, DataLength: uint64(len(data)), }) w.Write(data) return err } func MessageFromReader(reader io.Reader, m *Message) error { header := StorableMessageHeader{} err := binary.Read(reader, binary.LittleEndian, &header) if err != nil { return err } messageBytes := make([]byte, header.DataLength) _, err = reader.Read(messageBytes) if err != nil { return err } switch header.Type { case AddRequestType: msg := &messages.AddRequest{} err = proto.Unmarshal(messageBytes, msg) m.Content = msg case AddItemType: msg := &messages.AddItem{} err = proto.Unmarshal(messageBytes, msg) m.Content = msg default: return fmt.Errorf("unknown message type") } if err != nil { return err } return nil }