mirror of
https://github.com/ipfs/kubo.git
synced 2025-05-17 15:06:47 +08:00
261 lines
5.5 KiB
Go
261 lines
5.5 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
|
|
iface "github.com/ipfs/boxo/coreiface"
|
|
caopts "github.com/ipfs/boxo/coreiface/options"
|
|
"github.com/ipfs/boxo/coreiface/path"
|
|
"github.com/ipfs/boxo/ipld/merkledag"
|
|
ft "github.com/ipfs/boxo/ipld/unixfs"
|
|
"github.com/ipfs/go-cid"
|
|
ipld "github.com/ipfs/go-ipld-format"
|
|
)
|
|
|
|
type ObjectAPI HttpApi
|
|
|
|
type objectOut struct {
|
|
Hash string
|
|
}
|
|
|
|
func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) (ipld.Node, error) {
|
|
options, err := caopts.ObjectNewOptions(opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var n ipld.Node
|
|
switch options.Type {
|
|
case "empty":
|
|
n = new(merkledag.ProtoNode)
|
|
case "unixfs-dir":
|
|
n = ft.EmptyDirNode()
|
|
default:
|
|
return nil, fmt.Errorf("unknown object type: %s", options.Type)
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func (api *ObjectAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.ObjectPutOption) (path.Resolved, error) {
|
|
options, err := caopts.ObjectPutOptions(opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out objectOut
|
|
err = api.core().Request("object/put").
|
|
Option("inputenc", options.InputEnc).
|
|
Option("datafieldenc", options.DataType).
|
|
Option("pin", options.Pin).
|
|
FileBody(r).
|
|
Exec(ctx, &out)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := cid.Parse(out.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return path.IpfsPath(c), nil
|
|
}
|
|
|
|
func (api *ObjectAPI) Get(ctx context.Context, p path.Path) (ipld.Node, error) {
|
|
r, err := api.core().Block().Get(ctx, p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return merkledag.DecodeProtobuf(b)
|
|
}
|
|
|
|
func (api *ObjectAPI) Data(ctx context.Context, p path.Path) (io.Reader, error) {
|
|
resp, err := api.core().Request("object/data", p.String()).Send(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
return nil, resp.Error
|
|
}
|
|
|
|
//TODO: make Data return ReadCloser to avoid copying
|
|
defer resp.Close()
|
|
b := new(bytes.Buffer)
|
|
if _, err := io.Copy(b, resp.Output); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return b, nil
|
|
}
|
|
|
|
func (api *ObjectAPI) Links(ctx context.Context, p path.Path) ([]*ipld.Link, error) {
|
|
var out struct {
|
|
Links []struct {
|
|
Name string
|
|
Hash string
|
|
Size uint64
|
|
}
|
|
}
|
|
if err := api.core().Request("object/links", p.String()).Exec(ctx, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
res := make([]*ipld.Link, len(out.Links))
|
|
for i, l := range out.Links {
|
|
c, err := cid.Parse(l.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
res[i] = &ipld.Link{
|
|
Cid: c,
|
|
Name: l.Name,
|
|
Size: l.Size,
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
func (api *ObjectAPI) Stat(ctx context.Context, p path.Path) (*iface.ObjectStat, error) {
|
|
var out struct {
|
|
Hash string
|
|
NumLinks int
|
|
BlockSize int
|
|
LinksSize int
|
|
DataSize int
|
|
CumulativeSize int
|
|
}
|
|
if err := api.core().Request("object/stat", p.String()).Exec(ctx, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := cid.Parse(out.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &iface.ObjectStat{
|
|
Cid: c,
|
|
NumLinks: out.NumLinks,
|
|
BlockSize: out.BlockSize,
|
|
LinksSize: out.LinksSize,
|
|
DataSize: out.DataSize,
|
|
CumulativeSize: out.CumulativeSize,
|
|
}, nil
|
|
}
|
|
|
|
func (api *ObjectAPI) AddLink(ctx context.Context, base path.Path, name string, child path.Path, opts ...caopts.ObjectAddLinkOption) (path.Resolved, error) {
|
|
options, err := caopts.ObjectAddLinkOptions(opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out objectOut
|
|
err = api.core().Request("object/patch/add-link", base.String(), name, child.String()).
|
|
Option("create", options.Create).
|
|
Exec(ctx, &out)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := cid.Parse(out.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return path.IpfsPath(c), nil
|
|
}
|
|
|
|
func (api *ObjectAPI) RmLink(ctx context.Context, base path.Path, link string) (path.Resolved, error) {
|
|
var out objectOut
|
|
err := api.core().Request("object/patch/rm-link", base.String(), link).
|
|
Exec(ctx, &out)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := cid.Parse(out.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return path.IpfsPath(c), nil
|
|
}
|
|
|
|
func (api *ObjectAPI) AppendData(ctx context.Context, p path.Path, r io.Reader) (path.Resolved, error) {
|
|
var out objectOut
|
|
err := api.core().Request("object/patch/append-data", p.String()).
|
|
FileBody(r).
|
|
Exec(ctx, &out)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := cid.Parse(out.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return path.IpfsPath(c), nil
|
|
}
|
|
|
|
func (api *ObjectAPI) SetData(ctx context.Context, p path.Path, r io.Reader) (path.Resolved, error) {
|
|
var out objectOut
|
|
err := api.core().Request("object/patch/set-data", p.String()).
|
|
FileBody(r).
|
|
Exec(ctx, &out)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, err := cid.Parse(out.Hash)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return path.IpfsPath(c), nil
|
|
}
|
|
|
|
type change struct {
|
|
Type iface.ChangeType
|
|
Path string
|
|
Before cid.Cid
|
|
After cid.Cid
|
|
}
|
|
|
|
func (api *ObjectAPI) Diff(ctx context.Context, a path.Path, b path.Path) ([]iface.ObjectChange, error) {
|
|
var out struct {
|
|
Changes []change
|
|
}
|
|
if err := api.core().Request("object/diff", a.String(), b.String()).Exec(ctx, &out); err != nil {
|
|
return nil, err
|
|
}
|
|
res := make([]iface.ObjectChange, len(out.Changes))
|
|
for i, ch := range out.Changes {
|
|
res[i] = iface.ObjectChange{
|
|
Type: ch.Type,
|
|
Path: ch.Path,
|
|
}
|
|
if ch.Before != cid.Undef {
|
|
res[i].Before = path.IpfsPath(ch.Before)
|
|
}
|
|
if ch.After != cid.Undef {
|
|
res[i].After = path.IpfsPath(ch.After)
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (api *ObjectAPI) core() *HttpApi {
|
|
return (*HttpApi)(api)
|
|
}
|