/ core / coreapi / object.go
object.go
  1  package coreapi
  2  
  3  import (
  4  	"context"
  5  
  6  	dag "github.com/ipfs/boxo/ipld/merkledag"
  7  	"github.com/ipfs/boxo/ipld/merkledag/dagutils"
  8  	ft "github.com/ipfs/boxo/ipld/unixfs"
  9  	"github.com/ipfs/boxo/path"
 10  	coreiface "github.com/ipfs/kubo/core/coreiface"
 11  	caopts "github.com/ipfs/kubo/core/coreiface/options"
 12  	"go.opentelemetry.io/otel/attribute"
 13  	"go.opentelemetry.io/otel/trace"
 14  
 15  	"github.com/ipfs/kubo/tracing"
 16  )
 17  
 18  type ObjectAPI CoreAPI
 19  
 20  type Link struct {
 21  	Name, Hash string
 22  	Size       uint64
 23  }
 24  
 25  type Node struct {
 26  	Links []Link
 27  	Data  string
 28  }
 29  
 30  func (api *ObjectAPI) AddLink(ctx context.Context, base path.Path, name string, child path.Path, opts ...caopts.ObjectAddLinkOption) (path.ImmutablePath, error) {
 31  	ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AddLink", trace.WithAttributes(
 32  		attribute.String("base", base.String()),
 33  		attribute.String("name", name),
 34  		attribute.String("child", child.String()),
 35  	))
 36  	defer span.End()
 37  
 38  	options, err := caopts.ObjectAddLinkOptions(opts...)
 39  	if err != nil {
 40  		return path.ImmutablePath{}, err
 41  	}
 42  	span.SetAttributes(attribute.Bool("create", options.Create))
 43  
 44  	baseNd, err := api.core().ResolveNode(ctx, base)
 45  	if err != nil {
 46  		return path.ImmutablePath{}, err
 47  	}
 48  
 49  	childNd, err := api.core().ResolveNode(ctx, child)
 50  	if err != nil {
 51  		return path.ImmutablePath{}, err
 52  	}
 53  
 54  	basePb, ok := baseNd.(*dag.ProtoNode)
 55  	if !ok {
 56  		return path.ImmutablePath{}, dag.ErrNotProtobuf
 57  	}
 58  
 59  	var createfunc func() *dag.ProtoNode
 60  	if options.Create {
 61  		createfunc = ft.EmptyDirNode
 62  	}
 63  
 64  	e := dagutils.NewDagEditor(basePb, api.dag)
 65  
 66  	err = e.InsertNodeAtPath(ctx, name, childNd, createfunc)
 67  	if err != nil {
 68  		return path.ImmutablePath{}, err
 69  	}
 70  
 71  	nnode, err := e.Finalize(ctx, api.dag)
 72  	if err != nil {
 73  		return path.ImmutablePath{}, err
 74  	}
 75  
 76  	return path.FromCid(nnode.Cid()), nil
 77  }
 78  
 79  func (api *ObjectAPI) RmLink(ctx context.Context, base path.Path, link string) (path.ImmutablePath, error) {
 80  	ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "RmLink", trace.WithAttributes(
 81  		attribute.String("base", base.String()),
 82  		attribute.String("link", link)),
 83  	)
 84  	defer span.End()
 85  
 86  	baseNd, err := api.core().ResolveNode(ctx, base)
 87  	if err != nil {
 88  		return path.ImmutablePath{}, err
 89  	}
 90  
 91  	basePb, ok := baseNd.(*dag.ProtoNode)
 92  	if !ok {
 93  		return path.ImmutablePath{}, dag.ErrNotProtobuf
 94  	}
 95  
 96  	e := dagutils.NewDagEditor(basePb, api.dag)
 97  
 98  	err = e.RmLink(ctx, link)
 99  	if err != nil {
100  		return path.ImmutablePath{}, err
101  	}
102  
103  	nnode, err := e.Finalize(ctx, api.dag)
104  	if err != nil {
105  		return path.ImmutablePath{}, err
106  	}
107  
108  	return path.FromCid(nnode.Cid()), nil
109  }
110  
111  func (api *ObjectAPI) Diff(ctx context.Context, before path.Path, after path.Path) ([]coreiface.ObjectChange, error) {
112  	ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Diff", trace.WithAttributes(
113  		attribute.String("before", before.String()),
114  		attribute.String("after", after.String()),
115  	))
116  	defer span.End()
117  
118  	beforeNd, err := api.core().ResolveNode(ctx, before)
119  	if err != nil {
120  		return nil, err
121  	}
122  
123  	afterNd, err := api.core().ResolveNode(ctx, after)
124  	if err != nil {
125  		return nil, err
126  	}
127  
128  	changes, err := dagutils.Diff(ctx, api.dag, beforeNd, afterNd)
129  	if err != nil {
130  		return nil, err
131  	}
132  
133  	out := make([]coreiface.ObjectChange, len(changes))
134  	for i, change := range changes {
135  		out[i] = coreiface.ObjectChange{
136  			Type: coreiface.ChangeType(change.Type),
137  			Path: change.Path,
138  		}
139  
140  		if change.Before.Defined() {
141  			out[i].Before = path.FromCid(change.Before)
142  		}
143  
144  		if change.After.Defined() {
145  			out[i].After = path.FromCid(change.After)
146  		}
147  	}
148  
149  	return out, nil
150  }
151  
152  func (api *ObjectAPI) core() coreiface.CoreAPI {
153  	return (*CoreAPI)(api)
154  }