1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-05-20 08:27:29 +08:00
Files
kubo/core/coreapi/unixfile.go
Łukasz Magiera b10e718ab4 files2.0: no error from Entries
License: MIT
Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
2018-12-20 13:52:20 +01:00

158 lines
3.0 KiB
Go

package coreapi
import (
"context"
"errors"
files "gx/ipfs/QmXWZCd8jfaHmt4UDSnjKmGcrQMw95bDGWqEeVLVJjoANX/go-ipfs-files"
ft "gx/ipfs/Qmbvw7kpSM2p6rbQ57WGRhhqNfCiNGW6EKH4xgHLw4bsnB/go-unixfs"
uio "gx/ipfs/Qmbvw7kpSM2p6rbQ57WGRhhqNfCiNGW6EKH4xgHLw4bsnB/go-unixfs/io"
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
dag "gx/ipfs/QmdV35UHnL1FM52baPkeUo6u7Fxm2CRUkPTLRPxeF8a4Ap/go-merkledag"
)
// Number to file to prefetch in directories
// TODO: should we allow setting this via context hint?
const prefetchFiles = 4
// TODO: this probably belongs in go-unixfs (and could probably replace a chunk of it's interface in the long run)
type ufsDirectory struct {
ctx context.Context
dserv ipld.DAGService
dir uio.Directory
}
type ufsIterator struct {
ctx context.Context
files chan *ipld.Link
dserv ipld.DAGService
curName string
curFile files.Node
err error
}
func (it *ufsIterator) Name() string {
return it.curName
}
func (it *ufsIterator) Node() files.Node {
return it.curFile
}
func (it *ufsIterator) File() files.File {
f, _ := it.curFile.(files.File)
return f
}
func (it *ufsIterator) Dir() files.Directory {
d, _ := it.curFile.(files.Directory)
return d
}
func (it *ufsIterator) Next() bool {
l, ok := <-it.files
if !ok {
return false
}
it.curFile = nil
nd, err := l.GetNode(it.ctx, it.dserv)
if err != nil {
it.err = err
return false
}
it.curName = l.Name
it.curFile, it.err = newUnixfsFile(it.ctx, it.dserv, nd)
return it.err == nil
}
func (it *ufsIterator) Err() error {
return it.err
}
func (d *ufsDirectory) Close() error {
return nil
}
func (d *ufsDirectory) Entries() files.DirIterator {
fileCh := make(chan *ipld.Link, prefetchFiles)
go func() {
d.dir.ForEachLink(d.ctx, func(link *ipld.Link) error {
select {
case fileCh <- link:
case <-d.ctx.Done():
return d.ctx.Err()
}
return nil
})
close(fileCh)
}()
return &ufsIterator{
ctx: d.ctx,
files: fileCh,
dserv: d.dserv,
}
}
func (d *ufsDirectory) Size() (int64, error) {
return 0, files.ErrNotSupported
}
type ufsFile struct {
uio.DagReader
}
func (f *ufsFile) Size() (int64, error) {
return int64(f.DagReader.Size()), nil
}
func newUnixfsDir(ctx context.Context, dserv ipld.DAGService, nd ipld.Node) (files.Directory, error) {
dir, err := uio.NewDirectoryFromNode(dserv, nd)
if err != nil {
return nil, err
}
return &ufsDirectory{
ctx: ctx,
dserv: dserv,
dir: dir,
}, nil
}
func newUnixfsFile(ctx context.Context, dserv ipld.DAGService, nd ipld.Node) (files.Node, error) {
switch dn := nd.(type) {
case *dag.ProtoNode:
fsn, err := ft.FSNodeFromBytes(dn.Data())
if err != nil {
return nil, err
}
if fsn.IsDir() {
return newUnixfsDir(ctx, dserv, nd)
}
case *dag.RawNode:
default:
return nil, errors.New("unknown node type")
}
dr, err := uio.NewDagReader(ctx, nd, dserv)
if err != nil {
return nil, err
}
return &ufsFile{
DagReader: dr,
}, nil
}
var _ files.Directory = &ufsDirectory{}
var _ files.File = &ufsFile{}