package main import ( "bufio" "bytes" "encoding/binary" "fmt" "io" "git.tornberg.me/go-cart-actor/git.tornberg.me/go-cart-actor/messages" "google.golang.org/protobuf/proto" ) type StorableMessage interface { GetBytes() ([]byte, error) FromReader(io.Reader, *Message) error } type Message struct { Type uint64 TimeStamp *int64 Content interface{} } type MessageWriter struct { writer io.Writer } func NewMessageWriter(b *bytes.Buffer) *MessageWriter { return &MessageWriter{writer: bufio.NewWriter(b)} } func (w *MessageWriter) WriteUint64(value uint64) error { bytes := make([]byte, 8) binary.LittleEndian.PutUint64(bytes, value) _, err := w.writer.Write(bytes) return err } func (w *MessageWriter) WriteInt64(value int64) error { return w.WriteUint64(uint64(value)) } func (w *MessageWriter) WriteMessage(m *Message) error { if err := w.WriteUint64(m.Type); err != nil { return err } if err := w.WriteInt64(*m.TimeStamp); err != nil { return err } 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.writer.Write(messageBytes) return err } func (m Message) GetBytes() ([]byte, error) { var b bytes.Buffer mw := NewMessageWriter(&b) err := mw.WriteMessage(&m) return b.Bytes(), err } func (i Message) FromReader(reader io.Reader, m *Message) error { bytes := make([]byte, 8) if _, err := reader.Read(bytes); err != nil { return err } m.Type = binary.LittleEndian.Uint64(bytes) if _, err := reader.Read(bytes); err != nil { return err } timestamp := int64(binary.LittleEndian.Uint64(bytes)) m.TimeStamp = ×tamp if _, err := reader.Read(bytes); err != nil { return err } messageBytes := make([]byte, binary.LittleEndian.Uint64(bytes)) if _, err := reader.Read(messageBytes); err != nil { return err } var err error if m.Type == AddRequestType { msg := &messages.AddRequest{} err = proto.Unmarshal(messageBytes, msg) m.Content = msg } else if m.Type == AddItemType { msg := &messages.AddItem{} err = proto.Unmarshal(messageBytes, msg) m.Content = msg } else { return fmt.Errorf("unknown message type") } if err != nil { return err } return nil }