2018-07-04 16:30:24 +00:00
|
|
|
// Package local implements an ipfs-cluster Adder that chunks and adds content
|
|
|
|
// to a local peer, before pinning it.
|
|
|
|
package local
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2018-07-19 13:17:27 +00:00
|
|
|
"errors"
|
2018-07-04 16:30:24 +00:00
|
|
|
"mime/multipart"
|
|
|
|
|
|
|
|
"github.com/ipfs/ipfs-cluster/adder"
|
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
2018-07-19 14:27:23 +00:00
|
|
|
"github.com/ipfs/ipfs-cluster/rpcutil"
|
2018-07-04 16:30:24 +00:00
|
|
|
|
|
|
|
rpc "github.com/hsanjuan/go-libp2p-gorpc"
|
2018-08-06 10:44:44 +00:00
|
|
|
cid "github.com/ipfs/go-cid"
|
|
|
|
files "github.com/ipfs/go-ipfs-cmdkit/files"
|
2018-07-04 16:30:24 +00:00
|
|
|
logging "github.com/ipfs/go-log"
|
2018-08-06 10:44:44 +00:00
|
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
2018-07-04 16:30:24 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var logger = logging.Logger("addlocal")
|
|
|
|
|
2018-07-24 12:21:29 +00:00
|
|
|
// Adder is an implementation of IPFS Cluster Adder interface,
|
|
|
|
// which allows adding content directly to IPFS daemons attached
|
|
|
|
// to the Cluster (without sharding).
|
2018-07-04 16:30:24 +00:00
|
|
|
type Adder struct {
|
|
|
|
rpcClient *rpc.Client
|
|
|
|
}
|
|
|
|
|
2018-07-24 12:21:29 +00:00
|
|
|
// New returns a new Adder with the given rpc Client. The client is used
|
|
|
|
// to perform calls to IPFSBlockPut and Pin content on Cluster.
|
2018-07-04 16:30:24 +00:00
|
|
|
func New(rpc *rpc.Client) *Adder {
|
|
|
|
return &Adder{
|
|
|
|
rpcClient: rpc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 14:27:23 +00:00
|
|
|
func (a *Adder) putBlock(ctx context.Context, n *api.NodeWithMeta, dests []peer.ID) error {
|
|
|
|
logger.Debugf("put block: %s", n.Cid)
|
|
|
|
c, err := cid.Decode(n.Cid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
format, ok := cid.CodecToStr[c.Type()]
|
|
|
|
if !ok {
|
|
|
|
format = ""
|
|
|
|
logger.Warning("unsupported cid type, treating as v0")
|
|
|
|
}
|
|
|
|
if c.Prefix().Version == 0 {
|
|
|
|
format = "v0"
|
|
|
|
}
|
|
|
|
n.Format = format
|
|
|
|
|
|
|
|
ctxs, cancels := rpcutil.CtxsWithCancel(ctx, len(dests))
|
|
|
|
defer rpcutil.MultiCancel(cancels)
|
|
|
|
|
|
|
|
logger.Debugf("block put %s", n.Cid)
|
|
|
|
errs := a.rpcClient.MultiCall(
|
|
|
|
ctxs,
|
|
|
|
dests,
|
|
|
|
"Cluster",
|
|
|
|
"IPFSBlockPut",
|
|
|
|
*n,
|
|
|
|
rpcutil.RPCDiscardReplies(len(dests)),
|
|
|
|
)
|
|
|
|
return rpcutil.CheckErrs(errs)
|
|
|
|
}
|
|
|
|
|
2018-07-24 12:21:29 +00:00
|
|
|
// FromMultipart allows to add a file encoded as multipart.
|
2018-08-06 10:44:44 +00:00
|
|
|
func (a *Adder) FromMultipart(ctx context.Context, r *multipart.Reader, p *api.AddParams) (*cid.Cid, error) {
|
2018-07-04 16:30:24 +00:00
|
|
|
f := &files.MultipartFile{
|
|
|
|
Mediatype: "multipart/form-data",
|
|
|
|
Reader: r,
|
|
|
|
}
|
|
|
|
|
2018-07-19 14:27:23 +00:00
|
|
|
var allocsStr []string
|
|
|
|
err := a.rpcClient.CallContext(
|
|
|
|
ctx,
|
|
|
|
"",
|
|
|
|
"Cluster",
|
|
|
|
"Allocate",
|
|
|
|
api.PinWithOpts(nil, p.PinOptions).ToSerial(),
|
|
|
|
&allocsStr,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
allocations := api.StringsToPeers(allocsStr)
|
|
|
|
|
2018-07-04 16:30:24 +00:00
|
|
|
localBlockPut := func(ctx context.Context, n *api.NodeWithMeta) (string, error) {
|
|
|
|
retVal := n.Cid
|
2018-07-19 14:27:23 +00:00
|
|
|
return retVal, a.putBlock(ctx, n, allocations)
|
2018-07-04 16:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
importer, err := adder.NewImporter(f, p)
|
|
|
|
if err != nil {
|
2018-07-19 13:17:27 +00:00
|
|
|
return nil, err
|
2018-07-04 16:30:24 +00:00
|
|
|
}
|
|
|
|
|
2018-07-19 13:17:27 +00:00
|
|
|
lastCidStr, err := importer.Run(ctx, localBlockPut)
|
2018-07-04 16:30:24 +00:00
|
|
|
if err != nil {
|
2018-07-19 13:17:27 +00:00
|
|
|
return nil, err
|
2018-07-04 16:30:24 +00:00
|
|
|
}
|
|
|
|
|
2018-07-19 13:17:27 +00:00
|
|
|
lastCid, err := cid.Decode(lastCidStr)
|
|
|
|
if err != nil {
|
2018-07-24 12:21:29 +00:00
|
|
|
return nil, errors.New("nothing imported: invalid Cid")
|
2018-07-04 16:30:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, cluster pin the result
|
|
|
|
pinS := api.PinSerial{
|
2018-07-19 13:17:27 +00:00
|
|
|
Cid: lastCidStr,
|
2018-07-04 16:30:24 +00:00
|
|
|
Type: int(api.DataType),
|
|
|
|
MaxDepth: -1,
|
|
|
|
PinOptions: api.PinOptions{
|
|
|
|
ReplicationFactorMin: p.ReplicationFactorMin,
|
|
|
|
ReplicationFactorMax: p.ReplicationFactorMax,
|
|
|
|
Name: p.Name,
|
|
|
|
},
|
|
|
|
}
|
2018-07-19 13:17:27 +00:00
|
|
|
err = a.rpcClient.CallContext(
|
|
|
|
ctx,
|
2018-07-04 16:30:24 +00:00
|
|
|
"",
|
|
|
|
"Cluster",
|
|
|
|
"Pin",
|
|
|
|
pinS,
|
|
|
|
&struct{}{},
|
|
|
|
)
|
2018-07-19 13:17:27 +00:00
|
|
|
return lastCid, err
|
2018-07-04 16:30:24 +00:00
|
|
|
}
|