package coreunix
import (
"io"
"io/ioutil"
"os"
gopath "path"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
"github.com/ipfs/go-ipfs/commands/files"
core "github.com/ipfs/go-ipfs/core"
importer "github.com/ipfs/go-ipfs/importer"
chunk "github.com/ipfs/go-ipfs/importer/chunk"
merkledag "github.com/ipfs/go-ipfs/merkledag"
"github.com/ipfs/go-ipfs/pin"
"github.com/ipfs/go-ipfs/thirdparty/eventlog"
unixfs "github.com/ipfs/go-ipfs/unixfs"
)
var log = eventlog.Logger("coreunix")
// Add builds a merkledag from the a reader, pinning all objects to the local
// datastore. Returns a key representing the root node.
func Add(n *core.IpfsNode, r io.Reader) (string, error) {
// TODO more attractive function signature importer.BuildDagFromReader
dagNode, err := importer.BuildDagFromReader(
n.DAG,
chunk.NewSizeSplitter(r, chunk.DefaultBlockSize),
importer.BasicPinnerCB(n.Pinning.GetManual()),
)
if err != nil {
return "", err
}
k, err := dagNode.Key()
if err != nil {
return "", err
}
return k.String(), nil
}
// AddR recursively adds files in |path|.
func AddR(n *core.IpfsNode, root string) (key string, err error) {
f, err := os.Open(root)
if err != nil {
return "", err
}
defer f.Close()
ff, err := files.NewSerialFile(root, root, f)
if err != nil {
return "", err
}
dagnode, err := addFile(n, ff)
if err != nil {
return "", err
}
k, err := dagnode.Key()
if err != nil {
return "", err
}
n.Pinning.GetManual().RemovePinWithMode(k, pin.Indirect)
err = n.Pinning.Flush()
if err != nil {
return "", err
}
return k.String(), nil
}
// AddWrapped adds data from a reader, and wraps it with a directory object
// to preserve the filename.
// Returns the path of the added file ("
/filename"), the DAG node of
// the directory, and and error if any.
func AddWrapped(n *core.IpfsNode, r io.Reader, filename string) (string, *merkledag.Node, error) {
file := files.NewReaderFile(filename, filename, ioutil.NopCloser(r), nil)
dir := files.NewSliceFile("", "", []files.File{file})
dagnode, err := addDir(n, dir)
if err != nil {
return "", nil, err
}
k, err := dagnode.Key()
if err != nil {
return "", nil, err
}
return gopath.Join(k.String(), filename), dagnode, nil
}
func add(n *core.IpfsNode, reader io.Reader) (*merkledag.Node, error) {
mp := n.Pinning.GetManual()
node, err := importer.BuildDagFromReader(
n.DAG,
chunk.DefaultSplitter(reader),
importer.PinIndirectCB(mp),
)
if err != nil {
return nil, err
}
return node, nil
}
func addNode(n *core.IpfsNode, node *merkledag.Node) error {
err := n.DAG.AddRecursive(node) // add the file to the graph + local storage
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
defer cancel()
err = n.Pinning.Pin(ctx, node, true) // ensure we keep it
if err != nil {
return err
}
return nil
}
func addFile(n *core.IpfsNode, file files.File) (*merkledag.Node, error) {
if file.IsDirectory() {
return addDir(n, file)
}
dagnode, err := add(n, file)
if err != nil {
return nil, err
}
return dagnode, nil
}
func addDir(n *core.IpfsNode, dir files.File) (*merkledag.Node, error) {
tree := &merkledag.Node{Data: unixfs.FolderPBData()}
Loop:
for {
file, err := dir.NextFile()
switch {
case err != nil && err != io.EOF:
return nil, err
case err == io.EOF:
break Loop
}
node, err := addFile(n, file)
if err != nil {
return nil, err
}
_, name := gopath.Split(file.FileName())
err = tree.AddNodeLink(name, node)
if err != nil {
return nil, err
}
}
err := addNode(n, tree)
if err != nil {
return nil, err
}
return tree, nil
}