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" ) // 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() []*object.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 *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. // // 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) 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 *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 }