2021-10-27 12:12:05 +00:00
|
|
|
package neofsapiclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/ecdsa"
|
|
|
|
"fmt"
|
|
|
|
|
2022-01-13 15:01:50 +00:00
|
|
|
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
|
2021-10-27 12:12:05 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/storagegroup"
|
2021-11-10 07:08:33 +00:00
|
|
|
"github.com/nspcc-dev/neofs-sdk-go/client"
|
2021-11-06 11:13:04 +00:00
|
|
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
2021-11-10 07:08:33 +00:00
|
|
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
|
|
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
2021-10-27 12:12:05 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Client represents NeoFS API client cut down to the needs of a purely IR application.
|
|
|
|
type Client struct {
|
|
|
|
key *ecdsa.PrivateKey
|
|
|
|
|
2022-01-13 15:01:50 +00:00
|
|
|
c clientcore.Client
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// WrapBasicClient wraps client.Client instance to use it for NeoFS API RPC.
|
2022-01-13 15:01:50 +00:00
|
|
|
func (x *Client) WrapBasicClient(c clientcore.Client) {
|
2021-10-27 12:12:05 +00:00
|
|
|
x.c = c
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPrivateKey sets private key to sign RPC requests.
|
|
|
|
func (x *Client) SetPrivateKey(key *ecdsa.PrivateKey) {
|
|
|
|
x.key = key
|
|
|
|
}
|
|
|
|
|
|
|
|
// SearchSGPrm groups parameters of SearchSG operation.
|
|
|
|
type SearchSGPrm struct {
|
|
|
|
contextPrm
|
|
|
|
|
|
|
|
cnrID *cid.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetContainerID sets ID of the container to search for storage groups.
|
|
|
|
func (x *SearchSGPrm) SetContainerID(id *cid.ID) {
|
|
|
|
x.cnrID = id
|
|
|
|
}
|
|
|
|
|
|
|
|
// SearchSGRes groups resulting values of SearchSG operation.
|
|
|
|
type SearchSGRes struct {
|
2021-11-06 11:13:04 +00:00
|
|
|
cliRes *client.ObjectSearchRes
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// IDList returns list of IDs of storage groups in container.
|
|
|
|
func (x SearchSGRes) IDList() []*object.ID {
|
2021-11-06 11:13:04 +00:00
|
|
|
return x.cliRes.IDList()
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var sgFilter = storagegroup.SearchQuery()
|
|
|
|
|
|
|
|
// SearchSG lists objects of storage group type in the container.
|
2021-11-03 17:13:16 +00:00
|
|
|
//
|
|
|
|
// Returns any error prevented the operation from completing correctly in error return.
|
2021-10-27 12:12:05 +00:00
|
|
|
func (x Client) SearchSG(prm SearchSGPrm) (res SearchSGRes, err error) {
|
|
|
|
var cliPrm client.SearchObjectParams
|
|
|
|
|
|
|
|
cliPrm.WithContainerID(prm.cnrID)
|
|
|
|
cliPrm.WithSearchFilters(sgFilter)
|
|
|
|
|
2021-11-06 11:13:04 +00:00
|
|
|
res.cliRes, err = x.c.SearchObjects(prm.ctx, &cliPrm,
|
2021-10-27 12:12:05 +00:00
|
|
|
client.WithKey(x.key),
|
|
|
|
)
|
2021-11-06 11:13:04 +00:00
|
|
|
if err == nil {
|
|
|
|
// pull out an error from status
|
|
|
|
err = apistatus.ErrFromStatus(res.cliRes.Status())
|
|
|
|
}
|
2021-10-27 12:12:05 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetObjectPrm groups parameters of GetObject operation.
|
|
|
|
type GetObjectPrm struct {
|
|
|
|
getObjectPrm
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetObjectRes groups resulting values of GetObject operation.
|
|
|
|
type GetObjectRes struct {
|
2021-11-06 11:13:04 +00:00
|
|
|
cliRes *client.ObjectGetRes
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Object returns received object.
|
|
|
|
func (x GetObjectRes) Object() *object.Object {
|
2021-11-06 11:13:04 +00:00
|
|
|
return x.cliRes.Object()
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetObject reads the object by address.
|
2021-11-03 17:13:16 +00:00
|
|
|
//
|
|
|
|
// Returns any error prevented the operation from completing correctly in error return.
|
2021-10-27 12:12:05 +00:00
|
|
|
func (x Client) GetObject(prm GetObjectPrm) (res GetObjectRes, err error) {
|
|
|
|
var cliPrm client.GetObjectParams
|
|
|
|
|
|
|
|
cliPrm.WithAddress(prm.objAddr)
|
|
|
|
|
|
|
|
res.cliRes, err = x.c.GetObject(prm.ctx, &cliPrm,
|
|
|
|
client.WithKey(x.key),
|
|
|
|
)
|
2021-11-06 11:13:04 +00:00
|
|
|
if err == nil {
|
|
|
|
// pull out an error from status
|
|
|
|
err = apistatus.ErrFromStatus(res.cliRes.Status())
|
|
|
|
}
|
2021-10-27 12:12:05 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// HeadObjectPrm groups parameters of HeadObject operation.
|
|
|
|
type HeadObjectPrm struct {
|
|
|
|
getObjectPrm
|
|
|
|
|
|
|
|
raw bool
|
|
|
|
|
|
|
|
ttl uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetRawFlag sets flag of raw request.
|
|
|
|
func (x *HeadObjectPrm) SetRawFlag() {
|
|
|
|
x.raw = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTTL sets request TTL value.
|
|
|
|
func (x *HeadObjectPrm) SetTTL(ttl uint32) {
|
|
|
|
x.ttl = ttl
|
|
|
|
}
|
|
|
|
|
|
|
|
// HeadObjectRes groups resulting values of HeadObject operation.
|
|
|
|
type HeadObjectRes struct {
|
2021-11-06 11:13:04 +00:00
|
|
|
cliRes *client.ObjectHeadRes
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Header returns received object header.
|
|
|
|
func (x HeadObjectRes) Header() *object.Object {
|
2021-11-06 11:13:04 +00:00
|
|
|
return x.cliRes.Object()
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// HeadObject reads short object header by address.
|
|
|
|
//
|
2021-11-03 17:13:16 +00:00
|
|
|
// Returns any error prevented the operation from completing correctly in error return.
|
|
|
|
// For raw requests, returns *object.SplitInfoError error if requested object is virtual.
|
2021-10-27 12:12:05 +00:00
|
|
|
func (x Client) HeadObject(prm HeadObjectPrm) (res HeadObjectRes, err error) {
|
|
|
|
var cliPrm client.ObjectHeaderParams
|
|
|
|
|
|
|
|
cliPrm.WithAddress(prm.objAddr)
|
|
|
|
cliPrm.WithRawFlag(prm.raw)
|
|
|
|
cliPrm.WithMainFields()
|
|
|
|
|
2021-11-06 11:13:04 +00:00
|
|
|
res.cliRes, err = x.c.HeadObject(prm.ctx, &cliPrm,
|
2021-10-27 12:12:05 +00:00
|
|
|
client.WithKey(x.key),
|
|
|
|
client.WithTTL(prm.ttl),
|
|
|
|
)
|
2021-11-06 11:13:04 +00:00
|
|
|
if err == nil {
|
|
|
|
// pull out an error from status
|
|
|
|
err = apistatus.ErrFromStatus(res.cliRes.Status())
|
|
|
|
}
|
2021-10-27 12:12:05 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetObjectPayload reads object by address from NeoFS via Client and returns its payload.
|
2021-11-03 17:13:16 +00:00
|
|
|
//
|
|
|
|
// Returns any error prevented the operation from completing correctly in error return.
|
2021-10-27 12:12:05 +00:00
|
|
|
func GetObjectPayload(ctx context.Context, c Client, addr *object.Address) ([]byte, error) {
|
|
|
|
var prm GetObjectPrm
|
|
|
|
|
|
|
|
prm.SetContext(ctx)
|
|
|
|
prm.SetAddress(addr)
|
|
|
|
|
|
|
|
obj, err := c.GetObject(prm)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj.Object().Payload(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func headObject(ctx context.Context, c Client, addr *object.Address, raw bool, ttl uint32) (*object.Object, error) {
|
|
|
|
var prm HeadObjectPrm
|
|
|
|
|
|
|
|
prm.SetContext(ctx)
|
|
|
|
prm.SetAddress(addr)
|
|
|
|
prm.SetTTL(ttl)
|
|
|
|
|
|
|
|
if raw {
|
|
|
|
prm.SetRawFlag()
|
|
|
|
}
|
|
|
|
|
|
|
|
obj, err := c.HeadObject(prm)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return obj.Header(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRawObjectHeaderLocally reads raw short object header from server's local storage by address via Client.
|
|
|
|
func GetRawObjectHeaderLocally(ctx context.Context, c Client, addr *object.Address) (*object.Object, error) {
|
|
|
|
return headObject(ctx, c, addr, true, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetObjectHeaderFromContainer reads short object header by address via Client with TTL = 10
|
|
|
|
// for deep traversal of the container.
|
|
|
|
func GetObjectHeaderFromContainer(ctx context.Context, c Client, addr *object.Address) (*object.Object, error) {
|
|
|
|
return headObject(ctx, c, addr, false, 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HashPayloadRangePrm groups parameters of HashPayloadRange operation.
|
|
|
|
type HashPayloadRangePrm struct {
|
|
|
|
getObjectPrm
|
|
|
|
|
|
|
|
rng *object.Range
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetRange sets payload range to calculate the hash.
|
|
|
|
func (x *HashPayloadRangePrm) SetRange(rng *object.Range) {
|
|
|
|
x.rng = rng
|
|
|
|
}
|
|
|
|
|
|
|
|
// HashPayloadRangeRes groups resulting values of HashPayloadRange operation.
|
|
|
|
type HashPayloadRangeRes struct {
|
|
|
|
h []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hash returns hash of the object payload range.
|
|
|
|
func (x HashPayloadRangeRes) Hash() []byte {
|
|
|
|
return x.h
|
|
|
|
}
|
|
|
|
|
|
|
|
// HashObjectRange requests to calculate Tillich-Zemor hash of the payload range of the object
|
|
|
|
// from the remote server's local storage.
|
2021-11-03 17:13:16 +00:00
|
|
|
//
|
|
|
|
// Returns any error prevented the operation from completing correctly in error return.
|
2021-10-27 12:12:05 +00:00
|
|
|
func (x Client) HashPayloadRange(prm HashPayloadRangePrm) (res HashPayloadRangeRes, err error) {
|
|
|
|
var cliPrm client.RangeChecksumParams
|
|
|
|
|
|
|
|
cliPrm.WithAddress(prm.objAddr)
|
|
|
|
cliPrm.WithRangeList(prm.rng)
|
2022-02-14 09:33:04 +00:00
|
|
|
cliPrm.TZ()
|
2021-10-27 12:12:05 +00:00
|
|
|
|
2021-11-06 11:13:04 +00:00
|
|
|
cliRes, err := x.c.HashObjectPayloadRanges(prm.ctx, &cliPrm,
|
2021-10-27 12:12:05 +00:00
|
|
|
client.WithKey(x.key),
|
|
|
|
client.WithTTL(1),
|
|
|
|
)
|
|
|
|
if err == nil {
|
2021-11-06 11:13:04 +00:00
|
|
|
// pull out an error from status
|
|
|
|
err = apistatus.ErrFromStatus(cliRes.Status())
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
hs := cliRes.Hashes()
|
2021-10-27 12:12:05 +00:00
|
|
|
if ln := len(hs); ln != 1 {
|
|
|
|
err = fmt.Errorf("wrong number of hashes %d", ln)
|
|
|
|
} else {
|
2021-11-06 11:13:04 +00:00
|
|
|
res.h = hs[0]
|
2021-10-27 12:12:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// HashObjectRange reads Tillich-Zemor hash of the object payload range by address
|
|
|
|
// from the remote server's local storage via Client.
|
2021-11-03 17:13:16 +00:00
|
|
|
//
|
|
|
|
// Returns any error prevented the operation from completing correctly in error return.
|
2021-10-27 12:12:05 +00:00
|
|
|
func HashObjectRange(ctx context.Context, c Client, addr *object.Address, rng *object.Range) ([]byte, error) {
|
|
|
|
var prm HashPayloadRangePrm
|
|
|
|
|
|
|
|
prm.SetContext(ctx)
|
|
|
|
prm.SetAddress(addr)
|
|
|
|
prm.SetRange(rng)
|
|
|
|
|
|
|
|
res, err := c.HashPayloadRange(prm)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return res.Hash(), nil
|
|
|
|
}
|