frostfs-node/pkg/innerring/internal/client/client.go

285 lines
7.2 KiB
Go
Raw Normal View History

package neofsapiclient
import (
"context"
"crypto/ecdsa"
"fmt"
clientcore "github.com/nspcc-dev/neofs-node/pkg/core/client"
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/storagegroup"
"github.com/nspcc-dev/neofs-sdk-go/client"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/object"
addressSDK "github.com/nspcc-dev/neofs-sdk-go/object/address"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
// Client represents NeoFS API client cut down to the needs of a purely IR application.
type Client struct {
key *ecdsa.PrivateKey
c clientcore.Client
}
// WrapBasicClient wraps client.Client instance to use it for NeoFS API RPC.
func (x *Client) WrapBasicClient(c clientcore.Client) {
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 {
cliRes *client.ObjectSearchRes
}
// IDList returns list of IDs of storage groups in container.
func (x SearchSGRes) IDList() []*oid.ID {
return x.cliRes.IDList()
}
var sgFilter = storagegroup.SearchQuery()
// SearchSG lists objects of storage group type in the container.
//
// Returns any error prevented the operation from completing correctly in error return.
func (x Client) SearchSG(prm SearchSGPrm) (res SearchSGRes, err error) {
var cliPrm client.SearchObjectParams
cliPrm.WithContainerID(prm.cnrID)
cliPrm.WithSearchFilters(sgFilter)
res.cliRes, err = x.c.SearchObjects(prm.ctx, &cliPrm,
client.WithKey(x.key),
)
if err == nil {
// pull out an error from status
err = apistatus.ErrFromStatus(res.cliRes.Status())
}
return
}
// GetObjectPrm groups parameters of GetObject operation.
type GetObjectPrm struct {
getObjectPrm
}
// GetObjectRes groups resulting values of GetObject operation.
type GetObjectRes struct {
cliRes *client.ObjectGetRes
}
// Object returns received object.
func (x GetObjectRes) Object() *object.Object {
return x.cliRes.Object()
}
// GetObject reads the object by address.
//
// Returns any error prevented the operation from completing correctly in error return.
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),
)
if err == nil {
// pull out an error from status
err = apistatus.ErrFromStatus(res.cliRes.Status())
}
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 {
cliRes *client.ObjectHeadRes
}
// Header returns received object header.
func (x HeadObjectRes) Header() *object.Object {
return x.cliRes.Object()
}
// HeadObject reads short object header by address.
//
// Returns any error prevented the operation from completing correctly in error return.
// For raw requests, returns *object.SplitInfoError error if requested object is virtual.
func (x Client) HeadObject(prm HeadObjectPrm) (res HeadObjectRes, err error) {
var cliPrm client.ObjectHeaderParams
cliPrm.WithAddress(prm.objAddr)
cliPrm.WithRawFlag(prm.raw)
cliPrm.WithMainFields()
res.cliRes, err = x.c.HeadObject(prm.ctx, &cliPrm,
client.WithKey(x.key),
client.WithTTL(prm.ttl),
)
if err == nil {
// pull out an error from status
err = apistatus.ErrFromStatus(res.cliRes.Status())
}
return
}
// GetObjectPayload reads object by address from NeoFS via Client and returns its payload.
//
// Returns any error prevented the operation from completing correctly in error return.
func GetObjectPayload(ctx context.Context, c Client, addr *addressSDK.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 *addressSDK.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 *addressSDK.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 *addressSDK.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.
//
// Returns any error prevented the operation from completing correctly in error return.
func (x Client) HashPayloadRange(prm HashPayloadRangePrm) (res HashPayloadRangeRes, err error) {
var cliPrm client.RangeChecksumParams
cliPrm.WithAddress(prm.objAddr)
cliPrm.WithRangeList(prm.rng)
cliPrm.TZ()
cliRes, err := x.c.HashObjectPayloadRanges(prm.ctx, &cliPrm,
client.WithKey(x.key),
client.WithTTL(1),
)
if err == nil {
// pull out an error from status
err = apistatus.ErrFromStatus(cliRes.Status())
if err != nil {
return
}
hs := cliRes.Hashes()
if ln := len(hs); ln != 1 {
err = fmt.Errorf("wrong number of hashes %d", ln)
} else {
res.h = hs[0]
}
}
return
}
// HashObjectRange reads Tillich-Zemor hash of the object payload range by address
// from the remote server's local storage via Client.
//
// Returns any error prevented the operation from completing correctly in error return.
func HashObjectRange(ctx context.Context, c Client, addr *addressSDK.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
}