2024-09-18 12:53:31 +02:00
|
|
|
package container
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"io"
|
|
|
|
|
|
|
|
|
|
"github.com/ipfs/go-cid"
|
2024-09-19 21:26:42 +02:00
|
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
|
|
|
|
"github.com/multiformats/go-multihash"
|
2024-09-18 12:53:31 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// TODO: should the invocation being set as root in the car file?
|
|
|
|
|
|
|
|
|
|
type Container map[cid.Cid][]byte
|
|
|
|
|
|
|
|
|
|
func New() Container {
|
|
|
|
|
return make(Container)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func FromCar(r io.Reader) (Container, error) {
|
|
|
|
|
_, it, err := readCar(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c := New()
|
|
|
|
|
|
|
|
|
|
for block, err := range it {
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
c[block.c] = block.data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return c, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func FromCarBase64(r io.Reader) (Container, error) {
|
|
|
|
|
return FromCar(base64.NewDecoder(base64.StdEncoding, r))
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-19 21:26:42 +02:00
|
|
|
func FromCbor(r io.Reader) (Container, error) {
|
|
|
|
|
var raw [][]byte
|
|
|
|
|
err := cbor.DecodeReader(r, &raw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: the CID computation will likely be handled in the envelope
|
|
|
|
|
// TODO: the envelope should likely be able to deserialize arbitrary types based on the tag value
|
|
|
|
|
// TODO: the container should likely expose the decoded token, and have search methods (simple, but also DAG reconstruction, graph path search)
|
|
|
|
|
var cidBuilder = cid.V1Builder{Codec: cid.DagCBOR, MhType: multihash.SHA2_256}
|
|
|
|
|
|
|
|
|
|
ctn := make(Container, len(raw))
|
|
|
|
|
for _, bytes := range raw {
|
|
|
|
|
c, err := cidBuilder.Sum(bytes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
ctn[c] = bytes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ctn, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func FromCborBase64(r io.Reader) (Container, error) {
|
|
|
|
|
return FromCbor(base64.NewDecoder(base64.StdEncoding, r))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ctn Container) AddBytes(cid cid.Cid, data []byte) {
|
|
|
|
|
ctn[cid] = data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ctn Container) GetBytes(cid cid.Cid) ([]byte, bool) {
|
|
|
|
|
b, ok := ctn[cid]
|
|
|
|
|
return b, ok
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-18 12:53:31 +02:00
|
|
|
func (ctn Container) ToCar(w io.Writer) error {
|
|
|
|
|
return writeCar(w, nil, func(yield func(carBlock) bool) {
|
|
|
|
|
for c, bytes := range ctn {
|
|
|
|
|
if !yield(carBlock{c: c, data: bytes}) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ctn Container) ToCarBase64(w io.Writer) error {
|
|
|
|
|
w2 := base64.NewEncoder(base64.StdEncoding, w)
|
|
|
|
|
defer w2.Close()
|
|
|
|
|
return ctn.ToCar(w2)
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-19 21:26:42 +02:00
|
|
|
func (ctn Container) ToCbor(w io.Writer) error {
|
|
|
|
|
raw := make([][]byte, 0, len(ctn))
|
|
|
|
|
for _, bytes := range ctn {
|
|
|
|
|
raw = append(raw, bytes)
|
|
|
|
|
}
|
|
|
|
|
return cbor.EncodeWriter(raw, w)
|
2024-09-18 12:53:31 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-19 21:26:42 +02:00
|
|
|
func (ctn Container) ToCborBase64(w io.Writer) error {
|
|
|
|
|
w2 := base64.NewEncoder(base64.StdEncoding, w)
|
|
|
|
|
defer w2.Close()
|
|
|
|
|
return ctn.ToCbor(w2)
|
2024-09-18 12:53:31 +02:00
|
|
|
}
|