coreapi: asunc ls option
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Feb 1, 2019 at 20:12 UTC
d06a678e488b3498f0df1614413c18de35023cca
4 files changed
+86
-19
core/coreapi/interface/options/unixfs.go
+30
@@ -42,7 +42,12 @@ type UnixfsAddSettings struct {
42
Progress bool
43
}
44
45
+type UnixfsLsSettings struct {
46
+ Async bool
47
+}
48
+
49
type UnixfsAddOption func(*UnixfsAddSettings) error
50
+type UnixfsLsOption func(*UnixfsLsSettings) error
51
52
func UnixfsAddOptions(opts ...UnixfsAddOption) (*UnixfsAddSettings, cid.Prefix, error) {
53
options := &UnixfsAddSettings{
@@ -122,6 +127,21 @@ func UnixfsAddOptions(opts ...UnixfsAddOption) (*UnixfsAddSettings, cid.Prefix,
127
return options, prefix, nil
128
}
129
130
+func UnixfsLsOptions(opts ...UnixfsLsOption) (*UnixfsLsSettings, error) {
131
+ options := &UnixfsLsSettings{
132
+ Async: true,
133
+ }
134
+
135
+ for _, opt := range opts {
136
+ err := opt(options)
137
+ if err != nil {
138
+ return nil, err
139
+ }
140
+ }
141
+
142
+ return options, nil
143
+}
144
+
145
type unixfsOpts struct{}
146
147
var Unixfs unixfsOpts
@@ -290,3 +310,13 @@ func (unixfsOpts) Nocopy(enable bool) UnixfsAddOption {
310
return nil
311
}
312
}
313
+
314
+// Async tells ls to return results as soon as they are available, which can be
315
+// useful for listing HAMT directories. When this option is set to true returned
316
+// results won't be returned in order
317
+func (unixfsOpts) Async(async bool) UnixfsLsOption {
318
+ return func(settings *UnixfsLsSettings) error {
319
+ settings.Async = async
320
+ return nil
321
+ }
322
+}
core/coreapi/interface/tests/unixfs.go
+20
-2
@@ -749,12 +749,12 @@ func (tp *provider) TestLs(t *testing.T) {
749
t.Error(err)
750
}
751
752
- links, err := api.Unixfs().Ls(ctx, p)
752
+ links, err := api.Unixfs().Ls(ctx, p, options.Unixfs.Async(false))
753
if err != nil {
754
t.Error(err)
755
}
756
757
- link := <- links
757
+ link := (<-links).Link
758
if link.Size != 23 {
759
t.Fatalf("expected size = 23, got %d", link.Size)
760
}
@@ -768,6 +768,24 @@ func (tp *provider) TestLs(t *testing.T) {
768
t.Errorf("didn't expect a second link")
769
}
770
771
+ links, err = api.Unixfs().Ls(ctx, p, options.Unixfs.Async(true))
772
+ if err != nil {
773
+ t.Error(err)
774
+ }
775
+
776
+ link = (<-links).Link
777
+ if link.Size != 23 {
778
+ t.Fatalf("expected size = 23, got %d", link.Size)
779
+ }
780
+ if link.Name != "name-of-file" {
781
+ t.Fatalf("expected name = name-of-file, got %s", link.Name)
782
+ }
783
+ if link.Cid.String() != "QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr" {
784
+ t.Fatalf("expected cid = QmX3qQVKxDGz3URVC3861Z3CKtQKGBn6ffXRBBWGMFz9Lr, got %s", link.Cid)
785
+ }
786
+ if _, ok := <-links; ok {
787
+ t.Errorf("didn't expect a second link")
788
+ }
789
}
790
791
func (tp *provider) TestEntriesExpired(t *testing.T) {
core/coreapi/interface/unixfs.go
+3
-3
@@ -5,8 +5,8 @@ import (
5
6
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
7
8
- ipld "gx/ipfs/QmRL22E4paat7ky7vx9MLpR97JHHbFPrg3ytFQw6qp1y1s/go-ipld-format"
9
- files "gx/ipfs/QmaXvvAVAQ5ABqM5xtjYmV85xmN5MkWAZsX9H9Fwo4FVXp/go-ipfs-files"
8
+ ft "gx/ipfs/QmQ1JnYpnzkaurjW1yxkQxC2w3K1PorNE1nv1vaP5Le7sq/go-unixfs"
9
+ "gx/ipfs/QmaXvvAVAQ5ABqM5xtjYmV85xmN5MkWAZsX9H9Fwo4FVXp/go-ipfs-files"
10
)
11
12
type AddEvent struct {
@@ -31,5 +31,5 @@ type UnixfsAPI interface {
31
Get(context.Context, Path) (files.Node, error)
32
33
// Ls returns the list of links in a directory
34
- Ls(context.Context, Path) (<-chan *ipld.Link, error)
34
+ Ls(context.Context, Path, ...options.UnixfsLsOption) (<-chan ft.LinkResult, error)
35
}
core/coreapi/unixfs.go
+33
-14
@@ -143,30 +143,49 @@ func (api *UnixfsAPI) Get(ctx context.Context, p coreiface.Path) (files.Node, er
143
144
// Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format:
145
// `<link base58 hash> <link size in bytes> <link name>`
146
-func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path) (<-chan *ipld.Link, error) {
146
+func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path, opts ...options.UnixfsLsOption) (<-chan ft.LinkResult, error) {
147
+ settings, err := options.UnixfsLsOptions(opts...)
148
+ if err != nil {
149
+ return nil, err
150
+ }
151
+
152
dagnode, err := api.core().ResolveNode(ctx, p)
153
if err != nil {
154
return nil, err
155
}
156
152
- var ndlinks []*ipld.Link
157
dir, err := uio.NewDirectoryFromNode(api.dag, dagnode)
154
- switch err {
155
- case nil:
156
- l, err := dir.Links(ctx)
157
- if err != nil {
158
- return nil, err
159
- }
160
- ndlinks = l
161
- case uio.ErrNotADir:
162
- ndlinks = dagnode.Links()
163
- default:
158
+ if err == uio.ErrNotADir {
159
+ return lsFromLinks(dagnode.Links())
160
+ }
161
+ if err != nil {
162
+ return nil, err
163
+ }
164
+
165
+ if !settings.Async {
166
+ return lsFromDir(ctx, dir)
167
+ }
168
+
169
+ return lsFromLinksAsync(ctx, dir)
170
+}
171
+
172
+func lsFromLinksAsync(ctx context.Context, dir uio.Directory) (<-chan ft.LinkResult, error) {
173
+
174
+ return dir.EnumLinksAsync(ctx), nil
175
+}
176
+
177
+func lsFromDir(ctx context.Context, dir uio.Directory) (<-chan ft.LinkResult, error) {
178
+ l, err := dir.Links(ctx)
179
+ if err != nil {
180
return nil, err
181
}
182
+ return lsFromLinks(l)
183
+}
184
167
- links := make(chan *ipld.Link, len(ndlinks))
185
+func lsFromLinks(ndlinks []*ipld.Link) (<-chan ft.LinkResult, error) {
186
+ links := make(chan ft.LinkResult, len(ndlinks))
187
for _, l := range ndlinks {
169
- links <- &ipld.Link{Name: l.Name, Size: l.Size, Cid: l.Cid}
188
+ links <- ft.LinkResult{Link: &ipld.Link{Name: l.Name, Size: l.Size, Cid: l.Cid}}
189
}
190
close(links)
191
return links, nil