Explorar el Código

Implement event encoding/decoding for CBOR.

Arto Bendiken hace 3 años
padre
commit
347d690977
Se han modificado 4 ficheros con 107 adiciones y 16 borrados
  1. 72 7
      event.go
  2. 29 9
      event_test.go
  3. 2 0
      go.mod
  4. 4 0
      go.sum

+ 72 - 7
event.go

@@ -1,30 +1,55 @@
 package borealis
 
 import (
+	"bytes"
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
+	"reflect"
+
+	"github.com/fxamacker/cbor/v2"
 )
 
-type Event struct {
+type Event struct { // TODO: EventEnvelope or RawEvent
 	Type         uint16
 	TimestampS   uint32
 	TimestampMS  uint16
 	SequentialID uint64
 	UniqueID     []byte
-	Payload      interface{}
+	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) {
-	array := []interface{}{
+	return json.Marshal([]interface{}{
 		event.Type,
 		event.TimestampS,
 		event.TimestampMS,
 		event.SequentialID,
 		event.UniqueID, // automatically Base64-encoded
 		event.Payload,
-	}
-	return json.Marshal(array)
+	})
+}
+
+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 {
@@ -34,8 +59,9 @@ func (event *Event) UnmarshalJSON(input []byte) error {
 		return err
 	}
 	if len(array) != 6 {
-		return fmt.Errorf("event must be an array of length 6, got %d", len(array))
+		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))
@@ -44,6 +70,45 @@ func (event *Event) UnmarshalJSON(input []byte) error {
 	if err != nil {
 		return err
 	}
-	event.Payload = array[5]
+
+	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
 }

+ 29 - 9
event_test.go

@@ -1,9 +1,11 @@
 package borealis
 
 import (
+	"bytes"
 	"encoding/json"
-	"reflect"
 	"testing"
+
+	"github.com/fxamacker/cbor/v2"
 )
 
 var event = Event{
@@ -15,26 +17,44 @@ var event = Event{
 	Payload:      map[string]interface{}{},
 }
 var eventJSON = "[1,2,3,4,\"AAECAwQFBgcICQoLDA0ODw==\",{}]"
+var eventCBOR = []byte{0x86, 1, 2, 3, 4, 0x50, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0xa0}
 
-func TestEncodeEvent(t *testing.T) {
+func TestEncodeEventJSON(t *testing.T) {
 	output, err := json.Marshal(event)
 	if err != nil {
 		t.Error(err)
 	}
 	actual := string(output)
-	expected := eventJSON
-	if actual != expected {
-		t.Errorf("expected %v, but got %v", expected, actual)
+	if actual != eventJSON {
+		t.Errorf("expected %v, but got %v", eventJSON, actual)
+	}
+}
+
+func TestEncodeEventCBOR(t *testing.T) {
+	actual, err := cbor.Marshal(event)
+	if err != nil {
+		t.Error(err)
+	}
+	if !bytes.Equal(actual, eventCBOR) {
+		t.Errorf("expected %v, but got %v", eventCBOR, actual)
 	}
 }
 
-func TestDecodeEvent(t *testing.T) {
+func TestDecodeEventJSON(t *testing.T) {
 	var actual Event
 	if err := json.Unmarshal([]byte(eventJSON), &actual); err != nil {
 		t.Error(err)
 	}
-	expected := event
-	if !reflect.DeepEqual(actual, expected) {
-		t.Errorf("expected %v, but got %v", expected, actual)
+	if !event.Equal(actual) {
+		t.Errorf("expected %v, but got %v", event, actual)
+	}
+}
+func TestDecodeEventCBOR(t *testing.T) {
+	var actual Event
+	if err := cbor.Unmarshal([]byte(eventCBOR), &actual); err != nil {
+		t.Error(err)
+	}
+	if !event.Equal(actual) {
+		t.Errorf("expected %v, but got %v", event, actual)
 	}
 }

+ 2 - 0
go.mod

@@ -6,6 +6,7 @@ replace github.com/aurora-is-near/aurora-events/go v0.0.0 => ./events/go
 
 require (
 	github.com/aurora-is-near/aurora-events/go v0.0.0
+	github.com/fxamacker/cbor/v2 v2.3.0
 	github.com/mr-tron/base58 v1.2.0
 	github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc
 )
@@ -15,6 +16,7 @@ require (
 	github.com/nats-io/nats-server/v2 v2.6.6 // indirect
 	github.com/nats-io/nkeys v0.3.0 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
+	github.com/x448/float16 v0.8.4 // indirect
 	golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
 	google.golang.org/protobuf v1.27.1 // indirect
 )

+ 4 - 0
go.sum

@@ -1,3 +1,5 @@
+github.com/fxamacker/cbor/v2 v2.3.0 h1:aM45YGMctNakddNNAezPxDUpv38j44Abh+hifNuqXik=
+github.com/fxamacker/cbor/v2 v2.3.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -28,6 +30,8 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
 github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
 github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
 golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=