2024-10-02 11:56:32 +02:00
|
|
|
package container
|
|
|
|
|
|
|
|
|
|
import (
|
2024-11-21 15:49:29 +01:00
|
|
|
"bytes"
|
2024-10-02 11:56:32 +02:00
|
|
|
"io"
|
|
|
|
|
|
|
|
|
|
"github.com/ipld/go-ipld-prime"
|
2025-01-07 18:16:27 +01:00
|
|
|
"github.com/ipld/go-ipld-prime/codec/cbor"
|
2024-10-02 11:56:32 +02:00
|
|
|
"github.com/ipld/go-ipld-prime/datamodel"
|
|
|
|
|
"github.com/ipld/go-ipld-prime/fluent/qp"
|
|
|
|
|
"github.com/ipld/go-ipld-prime/node/basicnode"
|
|
|
|
|
)
|
|
|
|
|
|
2024-10-07 18:46:19 +02:00
|
|
|
// Writer is a token container writer. It provides a convenient way to aggregate and serialize tokens together.
|
2025-01-13 12:24:04 +01:00
|
|
|
type Writer map[string]struct{}
|
2024-10-02 11:56:32 +02:00
|
|
|
|
|
|
|
|
func NewWriter() Writer {
|
|
|
|
|
return make(Writer)
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-07 18:46:19 +02:00
|
|
|
// AddSealed includes a "sealed" token (serialized with a ToSealed* function) in the container.
|
2025-01-13 12:24:04 +01:00
|
|
|
func (ctn Writer) AddSealed(data []byte) {
|
|
|
|
|
ctn[string(data)] = struct{}{}
|
2024-10-02 11:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
// ToBytes encode the container into raw bytes.
|
|
|
|
|
func (ctn Writer) ToBytes() ([]byte, error) {
|
|
|
|
|
return ctn.toBytes(headerRawBytes)
|
|
|
|
|
}
|
2024-10-02 11:56:32 +02:00
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
// ToBytesWriter is the same as ToBytes, but with an io.Writer.
|
|
|
|
|
func (ctn Writer) ToBytesWriter(w io.Writer) error {
|
|
|
|
|
return ctn.toWriter(headerRawBytes, w)
|
2024-10-02 11:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
// ToBytesGzipped encode the container into gzipped bytes.
|
|
|
|
|
func (ctn Writer) ToBytesGzipped() ([]byte, error) {
|
|
|
|
|
return ctn.toBytes(headerRawBytesGzip)
|
2024-10-02 11:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
// ToBytesGzippedWriter is the same as ToBytesGzipped, but with an io.Writer.
|
|
|
|
|
func (ctn Writer) ToBytesGzippedWriter(w io.Writer) error {
|
|
|
|
|
return ctn.toWriter(headerRawBytesGzip, w)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToBase64StdPadding encode the container into a base64 string, with standard encoding and padding.
|
|
|
|
|
func (ctn Writer) ToBase64StdPadding() (string, error) {
|
|
|
|
|
return ctn.toString(headerBase64StdPadding)
|
2024-11-21 15:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
// ToBase64StdPaddingWriter is the same as ToBase64StdPadding, but with an io.Writer.
|
|
|
|
|
func (ctn Writer) ToBase64StdPaddingWriter(w io.Writer) error {
|
|
|
|
|
return ctn.toWriter(headerBase64StdPadding, w)
|
2024-11-21 15:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
// ToBase64StdPaddingGzipped encode the container into a pre-gzipped base64 string, with standard encoding and padding.
|
|
|
|
|
func (ctn Writer) ToBase64StdPaddingGzipped() (string, error) {
|
|
|
|
|
return ctn.toString(headerBase64StdPaddingGzip)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToBase64StdPaddingGzippedWriter is the same as ToBase64StdPaddingGzipped, but with an io.Writer.
|
|
|
|
|
func (ctn Writer) ToBase64StdPaddingGzippedWriter(w io.Writer) error {
|
|
|
|
|
return ctn.toWriter(headerBase64StdPaddingGzip, w)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToBase64URL encode the container into base64 string, with URL-safe encoding and no padding.
|
|
|
|
|
func (ctn Writer) ToBase64URL() (string, error) {
|
|
|
|
|
return ctn.toString(headerBase64URL)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToBase64URLWriter is the same as ToBase64URL, but with an io.Writer.
|
|
|
|
|
func (ctn Writer) ToBase64URLWriter(w io.Writer) error {
|
|
|
|
|
return ctn.toWriter(headerBase64URL, w)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToBase64URL encode the container into pre-gzipped base64 string, with URL-safe encoding and no padding.
|
2025-01-23 17:10:34 +01:00
|
|
|
func (ctn Writer) ToBase64URLGzipped() (string, error) {
|
2025-01-08 17:31:04 +01:00
|
|
|
return ctn.toString(headerBase64URLGzip)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ToBase64URLWriter is the same as ToBase64URL, but with an io.Writer.
|
|
|
|
|
func (ctn Writer) ToBase64URLGzipWriter(w io.Writer) error {
|
|
|
|
|
return ctn.toWriter(headerBase64URLGzip, w)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ctn Writer) toBytes(header header) ([]byte, error) {
|
2024-11-21 15:49:29 +01:00
|
|
|
var buf bytes.Buffer
|
2025-01-08 17:31:04 +01:00
|
|
|
err := ctn.toWriter(header, &buf)
|
2024-11-21 15:49:29 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
func (ctn Writer) toString(header header) (string, error) {
|
2024-11-21 15:49:29 +01:00
|
|
|
var buf bytes.Buffer
|
2025-01-08 17:31:04 +01:00
|
|
|
err := ctn.toWriter(header, &buf)
|
2024-11-21 15:49:29 +01:00
|
|
|
if err != nil {
|
2024-12-11 16:05:16 +01:00
|
|
|
return "", err
|
2024-11-21 15:49:29 +01:00
|
|
|
}
|
2024-12-11 16:05:16 +01:00
|
|
|
return buf.String(), nil
|
2024-11-21 15:49:29 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 17:31:04 +01:00
|
|
|
func (ctn Writer) toWriter(header header, w io.Writer) (err error) {
|
|
|
|
|
encoder := header.encoder(w)
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
err = encoder.Close()
|
|
|
|
|
}()
|
|
|
|
|
node, err := qp.BuildMap(basicnode.Prototype.Any, 1, func(ma datamodel.MapAssembler) {
|
|
|
|
|
qp.MapEntry(ma, containerVersionTag, qp.List(int64(len(ctn)), func(la datamodel.ListAssembler) {
|
2025-01-13 12:24:04 +01:00
|
|
|
for data, _ := range ctn {
|
|
|
|
|
qp.ListEntry(la, qp.Bytes([]byte(data)))
|
2025-01-08 17:31:04 +01:00
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ipld.EncodeStreaming(encoder, node, cbor.Encode)
|
2024-10-02 11:56:32 +02:00
|
|
|
}
|