Skip to content

Commit

Permalink
fix(unixfsnode): have reifier add path selection to normal nodes
Browse files Browse the repository at this point in the history
have reifier add path selection to all protobuf nodes, even ones that are not unixfs
  • Loading branch information
hannahhoward committed Apr 1, 2021
1 parent 67a7e38 commit d6733f6
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 21 deletions.
22 changes: 3 additions & 19 deletions directory/basicdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/ipfs/go-unixfsnode/data"
"github.com/ipfs/go-unixfsnode/iter"
"github.com/ipfs/go-unixfsnode/utils"
dagpb "github.com/ipld/go-codec-dagpb"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/schema"
Expand Down Expand Up @@ -33,7 +34,7 @@ func (n UnixFSBasicDir) Kind() ipld.Kind {
// LookupByString looks for the key in the list of links with a matching name
func (n UnixFSBasicDir) LookupByString(key string) (ipld.Node, error) {
links := n._substrate.FieldLinks()
link := lookup(links, key)
link := utils.Lookup(links, key)
if link == nil {
return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ipld.PathSegmentOfString(key)}
}
Expand Down Expand Up @@ -132,7 +133,7 @@ func (n UnixFSBasicDir) Iterator() *iter.UnixFSDir__Itr {
}

func (n UnixFSBasicDir) Lookup(key dagpb.String) dagpb.Link {
return lookup(n._substrate.FieldLinks(), key.String())
return utils.Lookup(n._substrate.FieldLinks(), key.String())
}

// direct access to the links and data
Expand All @@ -145,23 +146,6 @@ func (n UnixFSBasicDir) FieldData() dagpb.MaybeBytes {
return n._substrate.FieldData()
}

// we need to lookup by key in a list of dag pb links a fair amount, so just have
// a shortcut method
func lookup(links dagpb.PBLinks, key string) dagpb.Link {
li := links.Iterator()
for !li.Done() {
_, next := li.Next()
name := ""
if next.FieldName().Exists() {
name = next.FieldName().Must().String()
}
if key == name {
return next.FieldHash()
}
}
return nil
}

// Substrate returns the underlying PBNode -- note: only the substrate will encode successfully to protobuf if writing
func (n UnixFSBasicDir) Substrate() ipld.Node {
return n._substrate
Expand Down
142 changes: 142 additions & 0 deletions pathpbnode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package unixfsnode

import (
"github.com/ipfs/go-unixfsnode/iter"
"github.com/ipfs/go-unixfsnode/utils"
dagpb "github.com/ipld/go-codec-dagpb"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/schema"
)

var _ ipld.Node = PathedPBNode(nil)
var _ schema.TypedNode = PathedPBNode(nil)

type PathedPBNode = *_PathedPBNode

type _PathedPBNode struct {
_substrate dagpb.PBNode
}

func (n PathedPBNode) Kind() ipld.Kind {
return n._substrate.Kind()
}

// LookupByString looks for the key in the list of links with a matching name
func (n PathedPBNode) LookupByString(key string) (ipld.Node, error) {
links := n._substrate.FieldLinks()
link := utils.Lookup(links, key)
if link == nil {
return nil, schema.ErrNoSuchField{Type: nil /*TODO*/, Field: ipld.PathSegmentOfString(key)}
}
return link, nil
}

func (n PathedPBNode) LookupByNode(key ipld.Node) (ipld.Node, error) {
ks, err := key.AsString()
if err != nil {
return nil, err
}
return n.LookupByString(ks)
}

func (n PathedPBNode) LookupByIndex(idx int64) (ipld.Node, error) {
return n._substrate.LookupByIndex(idx)
}

func (n PathedPBNode) LookupBySegment(seg ipld.PathSegment) (ipld.Node, error) {
return n.LookupByString(seg.String())
}

func (n PathedPBNode) MapIterator() ipld.MapIterator {
return iter.NewUnixFSDirMapIterator(n._substrate.Links.Iterator(), nil)
}

// ListIterator returns an iterator which yields key-value pairs
// traversing the node.
// If the node kind is anything other than a list, nil will be returned.
//
// The iterator will yield every entry in the list; that is, it
// can be expected that itr.Next will be called node.Length times
// before itr.Done becomes true.
func (n PathedPBNode) ListIterator() ipld.ListIterator {
return nil
}

// Length returns the length of a list, or the number of entries in a map,
// or -1 if the node is not of list nor map kind.
func (n PathedPBNode) Length() int64 {
return n._substrate.FieldLinks().Length()
}

func (n PathedPBNode) IsAbsent() bool {
return false
}

func (n PathedPBNode) IsNull() bool {
return false
}

func (n PathedPBNode) AsBool() (bool, error) {
return n._substrate.AsBool()
}

func (n PathedPBNode) AsInt() (int64, error) {
return n._substrate.AsInt()
}

func (n PathedPBNode) AsFloat() (float64, error) {
return n._substrate.AsFloat()
}

func (n PathedPBNode) AsString() (string, error) {
return n._substrate.AsString()
}

func (n PathedPBNode) AsBytes() ([]byte, error) {
return n._substrate.AsBytes()
}

func (n PathedPBNode) AsLink() (ipld.Link, error) {
return n._substrate.AsLink()
}

func (n PathedPBNode) Prototype() ipld.NodePrototype {
// TODO: should this return something?
// probobly not until we write the write interfaces
return nil
}

// satisfy schema.TypedNode
func (PathedPBNode) Type() schema.Type {
return nil /*TODO:typelit*/
}

func (n PathedPBNode) Representation() ipld.Node {
return n._substrate.Representation()
}

// Native map accessors

func (n PathedPBNode) Iterator() *iter.UnixFSDir__Itr {

return iter.NewUnixFSDirIterator(n._substrate.Links.Iterator(), nil)
}

func (n PathedPBNode) Lookup(key dagpb.String) dagpb.Link {
return utils.Lookup(n._substrate.FieldLinks(), key.String())
}

// direct access to the links and data

func (n PathedPBNode) FieldLinks() dagpb.PBLinks {
return n._substrate.FieldLinks()
}

func (n PathedPBNode) FieldData() dagpb.MaybeBytes {
return n._substrate.FieldData()
}

// Substrate returns the underlying PBNode -- note: only the substrate will encode successfully to protobuf if writing
func (n PathedPBNode) Substrate() ipld.Node {
return n._substrate
}
10 changes: 8 additions & 2 deletions reification.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ func Reify(ctx context.Context, maybePBNodeRoot ipld.Node, lsys *ipld.LinkSystem
}
if !pbNode.FieldData().Exists() {
// no data field, therefore, not UnixFS
return pbNode, nil
return defaultReifier(ctx, pbNode, lsys)
}
data, err := data.DecodeUnixFSData(pbNode.Data.Must().Bytes())
if err != nil {
// we could not decode the UnixFS data, therefore, not UnixFS
return pbNode, nil
return defaultReifier(ctx, pbNode, lsys)
}
builder, ok := reifyFuncs[data.FieldDataType().Int()]
if !ok {
Expand All @@ -54,3 +54,9 @@ var reifyFuncs = map[int64]reifyTypeFunc{
data.Data_Directory: directory.NewUnixFSBasicDir,
data.Data_HAMTShard: hamt.NewUnixFSHAMTShard,
}

// treat non-unixFS nodes like directories -- allow them to lookup by link
// TODO: Make this a separate node as directors gain more functionality
func defaultReifier(_ context.Context, substrate dagpb.PBNode, _ *ipld.LinkSystem) (ipld.Node, error) {
return &_PathedPBNode{_substrate: substrate}, nil
}
19 changes: 19 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package utils

import dagpb "github.com/ipld/go-codec-dagpb"

// Lookup finds a name key in a list of dag pb links
func Lookup(links dagpb.PBLinks, key string) dagpb.Link {
li := links.Iterator()
for !li.Done() {
_, next := li.Next()
name := ""
if next.FieldName().Exists() {
name = next.FieldName().Must().String()
}
if key == name {
return next.FieldHash()
}
}
return nil
}

0 comments on commit d6733f6

Please sign in to comment.