package borealis import ( "bytes" "encoding/base64" "encoding/json" "fmt" "reflect" "github.com/fxamacker/cbor/v2" ) type Event struct { // TODO: EventEnvelope or RawEvent Type uint16 TimestampS uint32 TimestampMS uint16 SequentialID uint64 UniqueID []byte Payload map[string]interface{} } func (event Event) Equal(other Event) bool { if event.Type != other.Type || event.TimestampS != other.TimestampS || event.TimestampMS != other.TimestampMS || event.SequentialID != other.SequentialID || !bytes.Equal(event.UniqueID, other.UniqueID) { return false } return reflect.DeepEqual(event.Payload, other.Payload) } func (event Event) MarshalJSON() ([]byte, error) { return json.Marshal([]interface{}{ event.Type, event.TimestampS, event.TimestampMS, event.SequentialID, event.UniqueID, // automatically Base64-encoded event.Payload, }) } func (event Event) MarshalCBOR() ([]byte, error) { return cbor.Marshal([]interface{}{ event.Type, event.TimestampS, event.TimestampMS, event.SequentialID, event.UniqueID, event.Payload, }) } func (event *Event) UnmarshalJSON(input []byte) error { var err error array := []interface{}{} if err = json.Unmarshal(input, &array); err != nil { return err } if len(array) != 6 { return fmt.Errorf("event must be an array of length %d, but got %d", 6, len(array)) } event.Type = uint16(array[0].(float64)) event.TimestampS = uint32(array[1].(float64)) event.TimestampMS = uint16(array[2].(float64)) event.SequentialID = uint64(array[3].(float64)) event.UniqueID, err = base64.StdEncoding.DecodeString(array[4].(string)) if err != nil { return err } payload, ok := array[5].(map[string]interface{}) if !ok { return fmt.Errorf("event payload must be a map") } event.Payload = payload return nil } func (event *Event) UnmarshalCBOR(input []byte) error { var err error array := []interface{}{} if err = cbor.Unmarshal(input, &array); err != nil { return err } if len(array) != 6 { return fmt.Errorf("event must be an array of length %d, but got %d", 6, len(array)) } event.Type = uint16(array[0].(uint64)) event.TimestampS = uint32(array[1].(uint64)) event.TimestampMS = uint16(array[2].(uint64)) event.SequentialID = uint64(array[3].(uint64)) event.UniqueID = array[4].([]byte) payloadIn, ok := array[5].(map[interface{}]interface{}) if !ok { return fmt.Errorf("event payload must be a map") } payloadOut := make(map[string]interface{}) for k, v := range payloadIn { var key string if key, ok = k.(string); !ok { return fmt.Errorf("event payload must be a map with string keys, but got the key %v", k) } payloadOut[key] = v } event.Payload = payloadOut return nil }