diff --git a/core/coreapi/interface/options/unixfs.go b/core/coreapi/interface/options/unixfs.go
index 819cc3b6b..6dbab93b6 100644
--- a/core/coreapi/interface/options/unixfs.go
+++ b/core/coreapi/interface/options/unixfs.go
@@ -44,6 +44,9 @@ type UnixfsAddSettings struct {
type UnixfsLsSettings struct {
Async bool
+
+ ResolveType bool
+ ResolveSize bool
}
type UnixfsAddOption func(*UnixfsAddSettings) error
@@ -320,3 +323,17 @@ func (unixfsOpts) Async(async bool) UnixfsLsOption {
return nil
}
}
+
+func (unixfsOpts) ResolveSize(resolve bool) UnixfsLsOption {
+ return func(settings *UnixfsLsSettings) error {
+ settings.ResolveSize = resolve
+ return nil
+ }
+}
+
+func (unixfsOpts) ResolveType(resolve bool) UnixfsLsOption {
+ return func(settings *UnixfsLsSettings) error {
+ settings.ResolveSize = resolve
+ return nil
+ }
+}
\ No newline at end of file
diff --git a/core/coreapi/interface/unixfs.go b/core/coreapi/interface/unixfs.go
index ba2673fee..846b74629 100644
--- a/core/coreapi/interface/unixfs.go
+++ b/core/coreapi/interface/unixfs.go
@@ -2,10 +2,10 @@ package iface
import (
"context"
-
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
- ft "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs"
+ "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/pb"
+ ipld "gx/ipfs/QmRL22E4paat7ky7vx9MLpR97JHHbFPrg3ytFQw6qp1y1s/go-ipld-format"
"gx/ipfs/QmaXvvAVAQ5ABqM5xtjYmV85xmN5MkWAZsX9H9Fwo4FVXp/go-ipfs-files"
)
@@ -16,6 +16,14 @@ type AddEvent struct {
Size string `json:",omitempty"`
}
+type LsLink struct {
+ Link *ipld.Link
+ Size uint64
+ Type unixfs_pb.Data_DataType
+
+ Err error
+}
+
// UnixfsAPI is the basic interface to immutable files in IPFS
// NOTE: This API is heavily WIP, things are guaranteed to break frequently
type UnixfsAPI interface {
@@ -31,5 +39,5 @@ type UnixfsAPI interface {
Get(context.Context, Path) (files.Node, error)
// Ls returns the list of links in a directory
- Ls(context.Context, Path, ...options.UnixfsLsOption) (<-chan ft.LinkResult, error)
+ Ls(context.Context, Path, ...options.UnixfsLsOption) (<-chan LsLink, error)
}
diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go
index 5d23d360d..9a66de3ca 100644
--- a/core/coreapi/unixfs.go
+++ b/core/coreapi/unixfs.go
@@ -15,11 +15,13 @@ import (
unixfile "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/file"
uio "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs/io"
mfs "gx/ipfs/QmR66iEqVtNMbbZxTHPY3F6W5QLFqZEDbFD7gzbE9HpYXU/go-mfs"
+ cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
ipld "gx/ipfs/QmRL22E4paat7ky7vx9MLpR97JHHbFPrg3ytFQw6qp1y1s/go-ipld-format"
bstore "gx/ipfs/QmS2aqUZLJp8kF1ihE5rvDGE5LvmKDPnx32w9Z1BW9xLV5/go-ipfs-blockstore"
blockservice "gx/ipfs/QmVKQHuzni68SWByzJgBUCwHvvr4TWiXfutNWWwpZpp4rE/go-blockservice"
files "gx/ipfs/QmaXvvAVAQ5ABqM5xtjYmV85xmN5MkWAZsX9H9Fwo4FVXp/go-ipfs-files"
dag "gx/ipfs/Qmb2UEG2TAeVrEJSjqsZF7Y2he7wRDkrdt6c3bECxwZf4k/go-merkledag"
+ merkledag "gx/ipfs/Qmb2UEG2TAeVrEJSjqsZF7Y2he7wRDkrdt6c3bECxwZf4k/go-merkledag"
dagtest "gx/ipfs/Qmb2UEG2TAeVrEJSjqsZF7Y2he7wRDkrdt6c3bECxwZf4k/go-merkledag/test"
cidutil "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil"
)
@@ -143,7 +145,7 @@ func (api *UnixfsAPI) Get(ctx context.Context, p coreiface.Path) (files.Node, er
// Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format:
// ` `
-func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path, opts ...options.UnixfsLsOption) (<-chan ft.LinkResult, error) {
+func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path, opts ...options.UnixfsLsOption) (<-chan coreiface.LsLink, error) {
settings, err := options.UnixfsLsOptions(opts...)
if err != nil {
return nil, err
@@ -156,36 +158,93 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path, opts ...options.
dir, err := uio.NewDirectoryFromNode(api.dag, dagnode)
if err == uio.ErrNotADir {
- return lsFromLinks(dagnode.Links())
+ return api.lsFromLinks(ctx, dagnode.Links(), settings)
}
if err != nil {
return nil, err
}
if !settings.Async {
- return lsFromDir(ctx, dir)
+ return api.lsFromDir(ctx, dir, settings)
}
- return lsFromLinksAsync(ctx, dir)
+ return api.lsFromLinksAsync(ctx, dir, settings)
}
-func lsFromLinksAsync(ctx context.Context, dir uio.Directory) (<-chan ft.LinkResult, error) {
+func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, settings *options.UnixfsLsSettings) coreiface.LsLink {
+ lnk := coreiface.LsLink{
+ Link: linkres.Link,
+ Err: linkres.Err,
+ }
+ if lnk.Err != nil {
+ return lnk
+ }
- return dir.EnumLinksAsync(ctx), nil
+ switch lnk.Link.Cid.Type() {
+ case cid.Raw:
+ // No need to check with raw leaves
+ lnk.Type = ft.TFile
+ lnk.Size = lnk.Link.Size
+ case cid.DagProtobuf:
+ if !settings.ResolveSize && !settings.ResolveType {
+ break
+ }
+
+ linkNode, err := lnk.Link.GetNode(ctx, api.dag)
+ if err != nil {
+ lnk.Err = err
+ break
+ }
+
+ if pn, ok := linkNode.(*merkledag.ProtoNode); ok {
+ d, err := ft.FSNodeFromBytes(pn.Data())
+ if err != nil {
+ lnk.Err = err
+ break
+ }
+ if settings.ResolveType {
+ lnk.Type = d.Type()
+ }
+ if d.Type() == ft.TFile && settings.ResolveSize {
+ lnk.Size = d.FileSize()
+ }
+ }
+ }
+
+ return lnk
}
-func lsFromDir(ctx context.Context, dir uio.Directory) (<-chan ft.LinkResult, error) {
+func (api *UnixfsAPI) lsFromLinksAsync(ctx context.Context, dir uio.Directory, settings *options.UnixfsLsSettings) (<-chan coreiface.LsLink, error) {
+ out := make(chan coreiface.LsLink)
+
+ go func() {
+ defer close(out)
+ for l := range dir.EnumLinksAsync(ctx) {
+ select {
+ case out <- api.processLink(ctx, l, settings): //TODO: perf: processing can be done in background and in parallel
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return out, nil
+}
+
+func (api *UnixfsAPI) lsFromDir(ctx context.Context, dir uio.Directory, settings *options.UnixfsLsSettings) (<-chan coreiface.LsLink, error) {
l, err := dir.Links(ctx)
if err != nil {
return nil, err
}
- return lsFromLinks(l)
+ return api.lsFromLinks(ctx, l, settings)
}
-func lsFromLinks(ndlinks []*ipld.Link) (<-chan ft.LinkResult, error) {
- links := make(chan ft.LinkResult, len(ndlinks))
+func (api *UnixfsAPI) lsFromLinks(ctx context.Context, ndlinks []*ipld.Link, settings *options.UnixfsLsSettings) (<-chan coreiface.LsLink, error) {
+ links := make(chan coreiface.LsLink, len(ndlinks))
for _, l := range ndlinks {
- links <- ft.LinkResult{Link: &ipld.Link{Name: l.Name, Size: l.Size, Cid: l.Cid}}
+ lr := ft.LinkResult{Link: &ipld.Link{Name: l.Name, Size: l.Size, Cid: l.Cid}}
+
+ links <- api.processLink(ctx, lr, settings) //TODO: can be parallel if settings.Async
}
close(links)
return links, nil