package domain import ( "fmt" "git.michelsen.id/phill/chron/chron-note/internal/util" ) type EventType uint8 const ( EventObjectUpsert EventType = 1 EventObjectDelete EventType = 2 ) const encodingVersion uint8 = 1 type ObjectUpsert struct { ObjectID ObjectID Name string Tags []string HasBlob bool Blob BlobID } type ObjectDelete struct { ObjectID ObjectID } type Event struct { Type EventType Upsert *ObjectUpsert Delete *ObjectDelete } func EncodeEvent(e Event) ([]byte, error) { enc := util.NewEncoder(nil) enc.U8(encodingVersion) enc.U8(uint8(e.Type)) switch e.Type { case EventObjectUpsert: if e.Upsert == nil { return nil, ErrInvalidEvent } u := e.Upsert var flags uint8 if u.HasBlob { flags |= 0x01 } enc.U8(flags) enc.BytesFixed(u.ObjectID[:]) enc.String(u.Name) enc.StringSlice(u.Tags) if u.HasBlob { enc.BytesFixed(u.Blob[:]) } case EventObjectDelete: if e.Delete == nil { return nil, ErrInvalidEvent } enc.BytesFixed(e.Delete.ObjectID[:]) default: return nil, ErrUnknownEventType } if err := enc.Err(); err != nil { return nil, err } return enc.Bytes(), nil } func DecodeEvent(b []byte) (Event, error) { dec := util.NewDecoder(b) ver := dec.U8() if dec.Err() != nil { return Event{}, ErrDecode } if ver != encodingVersion { return Event{}, fmt.Errorf("%w: unsupported encoding version %d", ErrDecode, ver) } typ := EventType(dec.U8()) if dec.Err() != nil { return Event{}, ErrDecode } switch typ { case EventObjectUpsert: flags := dec.U8() var objID ObjectID copy(objID[:], dec.BytesFixed(len(objID))) name := dec.String() tags := dec.StringSlice() hasBlob := (flags & 0x01) != 0 var blob BlobID if hasBlob { copy(blob[:], dec.BytesFixed(len(blob))) } if dec.Err() != nil { return Event{}, ErrDecode } return Event{ Type: typ, Upsert: &ObjectUpsert{ ObjectID: objID, Name: NormalizeName(name), Tags: NormalizeTags(tags), HasBlob: hasBlob, Blob: blob, }, }, nil case EventObjectDelete: var objID ObjectID copy(objID[:], dec.BytesFixed(len(objID))) if dec.Err() != nil { return Event{}, ErrDecode } return Event{Type: typ, Delete: &ObjectDelete{ObjectID: objID}}, nil default: return Event{}, ErrUnknownEventType } }