diff --git a/pkg/container/reader.go b/pkg/container/reader.go index db1e145..315feda 100644 --- a/pkg/container/reader.go +++ b/pkg/container/reader.go @@ -98,13 +98,32 @@ func FromCbor(r io.Reader) (Reader, error) { if err != nil { return nil, err } - if n.Kind() != datamodel.Kind_List { - return nil, fmt.Errorf("not a list") + if n.Kind() != datamodel.Kind_Map { + return nil, fmt.Errorf("invalid container format: expected map") } - ctn := make(Reader, n.Length()) + vNode, err := n.LookupByString("version") + if err != nil { + return nil, fmt.Errorf("invalid container format: missing version") + } + version, err := vNode.AsString() + if err != nil { + return nil, fmt.Errorf("invalid container format: version must be string") + } + if version != defaultContainerVersion { + return nil, fmt.Errorf("unsupported container version: %s", version) + } - it := n.ListIterator() + tokensNode, err := n.LookupByString("tokens") + if err != nil { + return nil, fmt.Errorf("invalid container format: missing tokens") + } + if tokensNode.Kind() != datamodel.Kind_List { + return nil, fmt.Errorf("invalid container format: tokens must be a list") + } + + ctn := make(Reader, tokensNode.Length()) + it := tokensNode.ListIterator() for !it.Done() { _, val, err := it.Next() if err != nil { @@ -119,6 +138,7 @@ func FromCbor(r io.Reader) (Reader, error) { return nil, err } } + return ctn, nil } diff --git a/pkg/container/writer.go b/pkg/container/writer.go index de6ec42..1f0309f 100644 --- a/pkg/container/writer.go +++ b/pkg/container/writer.go @@ -14,6 +14,8 @@ import ( // TODO: should we have a multibase to wrap the cbor? but there is no reader/write in go-multibase :-( +const defaultContainerVersion = "ctn-v1" + // Writer is a token container writer. It provides a convenient way to aggregate and serialize tokens together. type Writer map[cid.Cid][]byte @@ -44,10 +46,14 @@ func (ctn Writer) ToCarBase64(w io.Writer) error { } func (ctn Writer) ToCbor(w io.Writer) error { - node, err := qp.BuildList(basicnode.Prototype.Any, int64(len(ctn)), func(la datamodel.ListAssembler) { - for _, bytes := range ctn { - qp.ListEntry(la, qp.Bytes(bytes)) - } + // Create a map with version and tokens + node, err := qp.BuildMap(basicnode.Prototype.Any, 2, func(ma datamodel.MapAssembler) { + qp.MapEntry(ma, "version", qp.String(defaultContainerVersion)) + qp.MapEntry(ma, "tokens", qp.List(int64(len(ctn)), func(la datamodel.ListAssembler) { + for _, bytes := range ctn { + qp.ListEntry(la, qp.Bytes(bytes)) + } + })) }) if err != nil { return err