package blockstore import ( "context" "io" "golang.org/x/xerrors" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" ) var _ Blockstore = (*idstore)(nil) type idstore struct { bs Blockstore } func NewIDStore(bs Blockstore) Blockstore { return &idstore{bs: bs} } func decodeCid(cid cid.Cid) (inline bool, data []byte, err error) { if cid.Prefix().MhType != mh.IDENTITY { return false, nil, nil } dmh, err := mh.Decode(cid.Hash()) if err != nil { return false, nil, err } if dmh.Code == mh.IDENTITY { return true, dmh.Digest, nil } return false, nil, err } func (b *idstore) Has(cid cid.Cid) (bool, error) { inline, _, err := decodeCid(cid) if err != nil { return false, xerrors.Errorf("error decoding Cid: %w", err) } if inline { return true, nil } return b.bs.Has(cid) } func (b *idstore) Get(cid cid.Cid) (blocks.Block, error) { inline, data, err := decodeCid(cid) if err != nil { return nil, xerrors.Errorf("error decoding Cid: %w", err) } if inline { return blocks.NewBlockWithCid(data, cid) } return b.bs.Get(cid) } func (b *idstore) GetSize(cid cid.Cid) (int, error) { inline, data, err := decodeCid(cid) if err != nil { return 0, xerrors.Errorf("error decoding Cid: %w", err) } if inline { return len(data), err } return b.bs.GetSize(cid) } func (b *idstore) View(cid cid.Cid, cb func([]byte) error) error { inline, data, err := decodeCid(cid) if err != nil { return xerrors.Errorf("error decoding Cid: %w", err) } if inline { return cb(data) } return b.bs.View(cid, cb) } func (b *idstore) Put(blk blocks.Block) error { inline, _, err := decodeCid(blk.Cid()) if err != nil { return xerrors.Errorf("error decoding Cid: %w", err) } if inline { return nil } return b.bs.Put(blk) } func (b *idstore) PutMany(blks []blocks.Block) error { toPut := make([]blocks.Block, 0, len(blks)) for _, blk := range blks { inline, _, err := decodeCid(blk.Cid()) if err != nil { return xerrors.Errorf("error decoding Cid: %w", err) } if inline { continue } toPut = append(toPut, blk) } if len(toPut) > 0 { return b.bs.PutMany(toPut) } return nil } func (b *idstore) DeleteBlock(cid cid.Cid) error { inline, _, err := decodeCid(cid) if err != nil { return xerrors.Errorf("error decoding Cid: %w", err) } if inline { return nil } return b.bs.DeleteBlock(cid) } func (b *idstore) DeleteMany(cids []cid.Cid) error { toDelete := make([]cid.Cid, 0, len(cids)) for _, cid := range cids { inline, _, err := decodeCid(cid) if err != nil { return xerrors.Errorf("error decoding Cid: %w", err) } if inline { continue } toDelete = append(toDelete, cid) } if len(toDelete) > 0 { return b.bs.DeleteMany(toDelete) } return nil } func (b *idstore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) { return b.bs.AllKeysChan(ctx) } func (b *idstore) HashOnRead(enabled bool) { b.bs.HashOnRead(enabled) } func (b *idstore) Close() error { if c, ok := b.bs.(io.Closer); ok { return c.Close() } return nil }