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 (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 } m.Type = header.Type m.TimeStamp = &header.TimeStamp return nil }