@cryptotaxi247 / kubo / commits / 8dda69575

coreapi unixfs: unixfs.Get

License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>

Łukasz Magiera committed Oct 3, 2018 at 17:21 UTC 8dda69575a1c20fd9ed7e458a6cc0f44ebdd9bb3
3 files changed +216
core/coreapi/interface/unixfs.go
+8
@@ -13,8 +13,16 @@ import (
13 // NOTE: This API is heavily WIP, things are guaranteed to break frequently
14 type UnixfsAPI interface {
15 // Add imports the data from the reader into merkledag file
16 + //
17 + // TODO: a long useful comment on how to use this for many different scenarios
18 Add(context.Context, files.File, ...options.UnixfsAddOption) (ResolvedPath, error)
19
20 + // Get returns a read-only handle to a file tree referenced by a path
21 + //
22 + // Note that some implementations of this API may apply the specified context
23 + // to operations performed on the returned file
24 + Get(context.Context, Path) (files.File, error)
25 +
26 // Cat returns a reader for the file
27 Cat(context.Context, Path) (Reader, error)
28
core/coreapi/unixfile.go new
+199
@@ -0,0 +1,199 @@
1 +package coreapi
2 +
3 +import (
4 + "bytes"
5 + "context"
6 + "errors"
7 + "io"
8 + "io/ioutil"
9 + "os"
10 + gopath "path"
11 + "time"
12 +
13 + files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
14 + ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
15 + uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
16 + dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
17 + ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
18 +)
19 +
20 +// Number to file to prefetch in directories
21 +// TODO: should we allow setting this via context hint?
22 +const prefetchFiles = 4
23 +
24 +// TODO: this probably belongs in go-unixfs (and could probably replace a chunk of it's interface in the long run)
25 +
26 +type sizeInfo struct {
27 + size int64
28 + name string
29 + modTime time.Time
30 +}
31 +
32 +func (s *sizeInfo) Name() string {
33 + return s.name
34 +}
35 +
36 +func (s *sizeInfo) Size() int64 {
37 + return s.size
38 +}
39 +
40 +func (s *sizeInfo) Mode() os.FileMode {
41 + return 0444 // all read
42 +}
43 +
44 +func (s *sizeInfo) ModTime() time.Time {
45 + return s.modTime
46 +}
47 +
48 +func (s *sizeInfo) IsDir() bool {
49 + return false
50 +}
51 +
52 +func (s *sizeInfo) Sys() interface{} {
53 + return nil
54 +}
55 +
56 +type ufsDirectory struct {
57 + ctx context.Context
58 + dserv ipld.DAGService
59 +
60 + files chan *ipld.Link
61 +
62 + name string
63 + path string
64 +}
65 +
66 +func (d *ufsDirectory) Close() error {
67 + return files.ErrNotReader
68 +}
69 +
70 +func (d *ufsDirectory) Read(_ []byte) (int, error) {
71 + return 0, files.ErrNotReader
72 +}
73 +
74 +func (d *ufsDirectory) FileName() string {
75 + return d.name
76 +}
77 +
78 +func (d *ufsDirectory) FullPath() string {
79 + return d.path
80 +}
81 +
82 +func (d *ufsDirectory) IsDirectory() bool {
83 + return true
84 +}
85 +
86 +func (d *ufsDirectory) NextFile() (files.File, error) {
87 + l, ok := <-d.files
88 + if !ok {
89 + return nil, io.EOF
90 + }
91 +
92 + nd, err := l.GetNode(d.ctx, d.dserv)
93 + if err != nil {
94 + return nil, err
95 + }
96 +
97 + return newUnixfsFile(d.ctx, d.dserv, nd, l.Name, d)
98 +}
99 +
100 +type ufsFile struct {
101 + uio.DagReader
102 +
103 + name string
104 + path string
105 +}
106 +
107 +func (f *ufsFile) IsDirectory() bool {
108 + return false
109 +}
110 +
111 +func (f *ufsFile) NextFile() (files.File, error) {
112 + return nil, files.ErrNotDirectory
113 +}
114 +
115 +func (f *ufsFile) FileName() string {
116 + return f.name
117 +}
118 +
119 +func (f *ufsFile) FullPath() string {
120 + return f.path
121 +}
122 +
123 +func (f *ufsFile) Size() (int64, error) {
124 + return int64(f.DagReader.Size()), nil
125 +}
126 +
127 +func newUnixfsDir(ctx context.Context, dserv ipld.DAGService, nd ipld.Node, name string, path string) (files.File, error) {
128 + dir, err := uio.NewDirectoryFromNode(dserv, nd)
129 + if err != nil {
130 + return nil, err
131 + }
132 +
133 + fileCh := make(chan *ipld.Link, prefetchFiles)
134 + go func() {
135 + dir.ForEachLink(ctx, func(link *ipld.Link) error {
136 + select {
137 + case fileCh <- link:
138 + case <-ctx.Done():
139 + return ctx.Err()
140 + }
141 + return nil
142 + })
143 +
144 + close(fileCh)
145 + }()
146 +
147 + return &ufsDirectory{
148 + ctx: ctx,
149 + dserv: dserv,
150 +
151 + files: fileCh,
152 +
153 + name: name,
154 + path: path,
155 + }, nil
156 +}
157 +
158 +func newUnixfsFile(ctx context.Context, dserv ipld.DAGService, nd ipld.Node, name string, parent files.File) (files.File, error) {
159 + path := name
160 + if parent != nil {
161 + path = gopath.Join(parent.FullPath(), name)
162 + }
163 +
164 + switch dn := nd.(type) {
165 + case *dag.ProtoNode:
166 + fsn, err := ft.FSNodeFromBytes(nd.RawData())
167 + if err != nil {
168 + return nil, err
169 + }
170 + if fsn.IsDir() {
171 + return newUnixfsDir(ctx, dserv, nd, name, path)
172 + }
173 +
174 + case *dag.RawNode:
175 +
176 + r := ioutil.NopCloser(bytes.NewReader(dn.RawData()))
177 + fi := &sizeInfo{
178 + size: int64(len(dn.RawData())),
179 + }
180 +
181 + return files.NewReaderFile("", "", r, fi), nil
182 + default:
183 + return nil, errors.New("unknown node type")
184 + }
185 +
186 + dr, err := uio.NewDagReader(ctx, nd, dserv)
187 + if err != nil {
188 + return nil, err
189 + }
190 +
191 + return &ufsFile{
192 + DagReader: dr,
193 +
194 + name: name,
195 + path: path,
196 + }, nil
197 +}
198 +
199 +var _ os.FileInfo = &sizeInfo{}
core/coreapi/unixfs.go
+9
@@ -110,6 +110,15 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.File, opts ...options
110 return coreiface.IpfsPath(nd.Cid()), nil
111 }
112
113 +func (api *UnixfsAPI) Get(ctx context.Context, p coreiface.Path) (files.File, error) {
114 + nd, err := api.core().ResolveNode(ctx, p)
115 + if err != nil {
116 + return nil, err
117 + }
118 +
119 + return newUnixfsFile(ctx, api.node.DAG, nd, "", nil)
120 +}
121 +
122 // Cat returns the data contained by an IPFS or IPNS object(s) at path `p`.
123 func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) {
124 dget := api.node.DAG // TODO: use a session here once routing perf issues are resolved