forked from TrueCloudLab/frostfs-sdk-go
[#299] client: Do not use pointers to required response fields
In previous implementation `client` package provided access to nested response fields as pointers to them. This caused clients to handle nil cases even when the field presence in the response is required. Avoid returning pointers to required fields in response getters. This also reduces reference counter load and allows fields to be decoded directly without additional assignment. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
30bf79f075
commit
4e31b4f231
10 changed files with 150 additions and 160 deletions
|
@ -2,8 +2,6 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
|
v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
@ -32,17 +30,11 @@ func (x *PrmBalanceGet) SetAccount(id user.ID) {
|
||||||
type ResBalanceGet struct {
|
type ResBalanceGet struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
amount *accounting.Decimal
|
amount accounting.Decimal
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ResBalanceGet) setAmount(v *accounting.Decimal) {
|
|
||||||
x.amount = v
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amount returns current amount of funds on the NeoFS account as decimal number.
|
// Amount returns current amount of funds on the NeoFS account as decimal number.
|
||||||
//
|
func (x ResBalanceGet) Amount() accounting.Decimal {
|
||||||
// Client doesn't retain value so modification is safe.
|
|
||||||
func (x ResBalanceGet) Amount() *accounting.Decimal {
|
|
||||||
return x.amount
|
return x.amount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,21 +88,18 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
resp := r.(*v2accounting.BalanceResponse)
|
resp := r.(*v2accounting.BalanceResponse)
|
||||||
|
|
||||||
|
const fieldBalance = "balance"
|
||||||
|
|
||||||
bal := resp.GetBody().GetBalance()
|
bal := resp.GetBody().GetBalance()
|
||||||
if bal == nil {
|
if bal == nil {
|
||||||
cc.err = errors.New("missing balance field")
|
cc.err = newErrMissingResponseField(fieldBalance)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var d accounting.Decimal
|
cc.err = res.amount.ReadFromV2(*bal)
|
||||||
|
|
||||||
cc.err = d.ReadFromV2(*bal)
|
|
||||||
if cc.err != nil {
|
if cc.err != nil {
|
||||||
cc.err = fmt.Errorf("invalid balance: %w", cc.err)
|
cc.err = newErrInvalidResponseField(fieldBalance, cc.err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setAmount(&d)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
|
|
@ -251,7 +251,7 @@ func (x *contextCall) close() bool {
|
||||||
x.result(x.resp)
|
x.result(x.resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return x.err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// goes through all stages of sending a request and processing a response. Returns true if successful.
|
// goes through all stages of sending a request and processing a response. Returns true if successful.
|
||||||
|
|
|
@ -54,22 +54,16 @@ func (x *PrmContainerPut) WithinSession(s session.Container) {
|
||||||
type ResContainerPut struct {
|
type ResContainerPut struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
id *cid.ID
|
id cid.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns identifier of the container declared to be stored in the system.
|
// ID returns identifier of the container declared to be stored in the system.
|
||||||
// Used as a link to information about the container (in particular, you can
|
// Used as a link to information about the container (in particular, you can
|
||||||
// asynchronously check if the save was successful).
|
// asynchronously check if the save was successful).
|
||||||
//
|
func (x ResContainerPut) ID() cid.ID {
|
||||||
// Client doesn't retain value so modification is safe.
|
|
||||||
func (x ResContainerPut) ID() *cid.ID {
|
|
||||||
return x.id
|
return x.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResContainerPut) setID(id *cid.ID) {
|
|
||||||
x.id = id
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerPut sends request to save container in NeoFS.
|
// ContainerPut sends request to save container in NeoFS.
|
||||||
//
|
//
|
||||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||||
|
@ -150,17 +144,19 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon
|
||||||
}
|
}
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
resp := r.(*v2container.PutResponse)
|
resp := r.(*v2container.PutResponse)
|
||||||
var cID *cid.ID
|
|
||||||
|
const fieldCnrID = "container ID"
|
||||||
|
|
||||||
cidV2 := resp.GetBody().GetContainerID()
|
cidV2 := resp.GetBody().GetContainerID()
|
||||||
if cidV2 != nil {
|
if cidV2 == nil {
|
||||||
var c cid.ID
|
cc.err = newErrMissingResponseField(fieldCnrID)
|
||||||
_ = c.ReadFromV2(*cidV2)
|
return
|
||||||
|
|
||||||
cID = &c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setID(cID)
|
cc.err = res.id.ReadFromV2(*cidV2)
|
||||||
|
if cc.err != nil {
|
||||||
|
cc.err = newErrInvalidResponseField(fieldCnrID, cc.err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
@ -200,10 +196,6 @@ func (x ResContainerGet) Container() container.Container {
|
||||||
return x.cnr
|
return x.cnr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResContainerGet) setContainer(cnr container.Container) {
|
|
||||||
x.cnr = cnr
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerGet reads NeoFS container by ID.
|
// ContainerGet reads NeoFS container by ID.
|
||||||
//
|
//
|
||||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||||
|
@ -261,15 +253,10 @@ func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResCon
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var cnr container.Container
|
cc.err = res.cnr.ReadFromV2(*cnrV2)
|
||||||
|
if cc.err != nil {
|
||||||
err := cnr.ReadFromV2(*cnrV2)
|
cc.err = fmt.Errorf("invalid container in response: %w", cc.err)
|
||||||
if err != nil {
|
|
||||||
cc.err = fmt.Errorf("invalid container in response: %w", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setContainer(cnr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
@ -309,10 +296,6 @@ func (x ResContainerList) Containers() []cid.ID {
|
||||||
return x.ids
|
return x.ids
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResContainerList) setContainers(ids []cid.ID) {
|
|
||||||
x.ids = ids
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerList requests identifiers of the account-owned containers.
|
// ContainerList requests identifiers of the account-owned containers.
|
||||||
//
|
//
|
||||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||||
|
@ -364,13 +347,15 @@ func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResC
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
resp := r.(*v2container.ListResponse)
|
resp := r.(*v2container.ListResponse)
|
||||||
|
|
||||||
ids := make([]cid.ID, len(resp.GetBody().GetContainerIDs()))
|
res.ids = make([]cid.ID, len(resp.GetBody().GetContainerIDs()))
|
||||||
|
|
||||||
for i, cidV2 := range resp.GetBody().GetContainerIDs() {
|
for i, cidV2 := range resp.GetBody().GetContainerIDs() {
|
||||||
_ = ids[i].ReadFromV2(cidV2)
|
cc.err = res.ids[i].ReadFromV2(cidV2)
|
||||||
|
if cc.err != nil {
|
||||||
|
cc.err = fmt.Errorf("invalid ID in the response: %w", cc.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setContainers(ids)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
@ -527,20 +512,14 @@ func (x *PrmContainerEACL) SetContainer(id cid.ID) {
|
||||||
type ResContainerEACL struct {
|
type ResContainerEACL struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
table *eacl.Table
|
table eacl.Table
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table returns eACL table of the requested container.
|
// Table returns eACL table of the requested container.
|
||||||
//
|
func (x ResContainerEACL) Table() eacl.Table {
|
||||||
// Client doesn't retain value so modification is safe.
|
|
||||||
func (x ResContainerEACL) Table() *eacl.Table {
|
|
||||||
return x.table
|
return x.table
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResContainerEACL) setTable(table *eacl.Table) {
|
|
||||||
x.table = table
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerEACL reads eACL table of the NeoFS container.
|
// ContainerEACL reads eACL table of the NeoFS container.
|
||||||
//
|
//
|
||||||
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
// Exactly one return value is non-nil. By default, server status is returned in res structure.
|
||||||
|
@ -594,11 +573,13 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
resp := r.(*v2container.GetExtendedACLResponse)
|
resp := r.(*v2container.GetExtendedACLResponse)
|
||||||
|
|
||||||
body := resp.GetBody()
|
eACL := resp.GetBody().GetEACL()
|
||||||
|
if eACL == nil {
|
||||||
|
cc.err = newErrMissingResponseField("eACL")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
table := eacl.NewTableFromV2(body.GetEACL())
|
res.table = *eacl.NewTableFromV2(eACL)
|
||||||
|
|
||||||
res.setTable(table)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
@ -833,7 +814,7 @@ func SyncContainerWithNetwork(ctx context.Context, cnr *container.Container, c *
|
||||||
return fmt.Errorf("network info call: %w", err)
|
return fmt.Errorf("network info call: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
container.ApplyNetworkConfig(cnr, *res.Info())
|
container.ApplyNetworkConfig(cnr, res.Info())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
)
|
)
|
||||||
|
@ -92,3 +93,14 @@ func IsErrSessionNotFound(err error) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns error describing missing field with the given name.
|
||||||
|
func newErrMissingResponseField(name string) error {
|
||||||
|
return fmt.Errorf("missing %s field in the response", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns error describing invalid field (according to the NeoFS protocol)
|
||||||
|
// with the given name and format violation err.
|
||||||
|
func newErrInvalidResponseField(name string, err error) error {
|
||||||
|
return fmt.Errorf("invalid %s field in the response: %w", name, err)
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
|
||||||
rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc"
|
rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc"
|
||||||
|
@ -21,33 +19,21 @@ type PrmEndpointInfo struct {
|
||||||
type ResEndpointInfo struct {
|
type ResEndpointInfo struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
version *version.Version
|
version version.Version
|
||||||
|
|
||||||
ni *netmap.NodeInfo
|
ni netmap.NodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatestVersion returns latest NeoFS API protocol's version in use.
|
// LatestVersion returns latest NeoFS API protocol's version in use.
|
||||||
//
|
func (x ResEndpointInfo) LatestVersion() version.Version {
|
||||||
// Client doesn't retain value so modification is safe.
|
|
||||||
func (x ResEndpointInfo) LatestVersion() *version.Version {
|
|
||||||
return x.version
|
return x.version
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResEndpointInfo) setLatestVersion(ver *version.Version) {
|
|
||||||
x.version = ver
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeInfo returns information about the NeoFS node served on the remote endpoint.
|
// NodeInfo returns information about the NeoFS node served on the remote endpoint.
|
||||||
//
|
func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo {
|
||||||
// Client doesn't retain value so modification is safe.
|
|
||||||
func (x ResEndpointInfo) NodeInfo() *netmap.NodeInfo {
|
|
||||||
return x.ni
|
return x.ni
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResEndpointInfo) setNodeInfo(info *netmap.NodeInfo) {
|
|
||||||
x.ni = info
|
|
||||||
}
|
|
||||||
|
|
||||||
// EndpointInfo requests information about the storage node served on the remote endpoint.
|
// EndpointInfo requests information about the storage node served on the remote endpoint.
|
||||||
//
|
//
|
||||||
// Method can be used as a health check to see if node is alive and responds to requests.
|
// Method can be used as a health check to see if node is alive and responds to requests.
|
||||||
|
@ -93,31 +79,33 @@ func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEnd
|
||||||
|
|
||||||
body := resp.GetBody()
|
body := resp.GetBody()
|
||||||
|
|
||||||
var ver version.Version
|
const fieldVersion = "version"
|
||||||
if v2ver := body.GetVersion(); v2ver != nil {
|
|
||||||
cc.err = ver.ReadFromV2(*v2ver)
|
|
||||||
if cc.err != nil {
|
|
||||||
cc.err = fmt.Errorf("invalid version: %w", cc.err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.setLatestVersion(&ver)
|
|
||||||
|
|
||||||
nodeV2 := body.GetNodeInfo()
|
verV2 := body.GetVersion()
|
||||||
if nodeV2 == nil {
|
if verV2 == nil {
|
||||||
cc.err = errors.New("missing node info in response body")
|
cc.err = newErrMissingResponseField(fieldVersion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var node netmap.NodeInfo
|
cc.err = res.version.ReadFromV2(*verV2)
|
||||||
|
|
||||||
cc.err = node.ReadFromV2(*nodeV2)
|
|
||||||
if cc.err != nil {
|
if cc.err != nil {
|
||||||
cc.err = fmt.Errorf("invalid node info: %w", cc.err)
|
cc.err = newErrInvalidResponseField(fieldVersion, cc.err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setNodeInfo(&node)
|
const fieldNodeInfo = "node info"
|
||||||
|
|
||||||
|
nodeInfoV2 := body.GetNodeInfo()
|
||||||
|
if nodeInfoV2 == nil {
|
||||||
|
cc.err = newErrMissingResponseField(fieldNodeInfo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.err = res.ni.ReadFromV2(*nodeInfoV2)
|
||||||
|
if cc.err != nil {
|
||||||
|
cc.err = newErrInvalidResponseField(fieldNodeInfo, cc.err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
@ -137,20 +125,14 @@ type PrmNetworkInfo struct {
|
||||||
type ResNetworkInfo struct {
|
type ResNetworkInfo struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
info *netmap.NetworkInfo
|
info netmap.NetworkInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info returns structured information about the NeoFS network.
|
// Info returns structured information about the NeoFS network.
|
||||||
//
|
func (x ResNetworkInfo) Info() netmap.NetworkInfo {
|
||||||
// Client doesn't retain value so modification is safe.
|
|
||||||
func (x ResNetworkInfo) Info() *netmap.NetworkInfo {
|
|
||||||
return x.info
|
return x.info
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ResNetworkInfo) setInfo(info *netmap.NetworkInfo) {
|
|
||||||
x.info = info
|
|
||||||
}
|
|
||||||
|
|
||||||
// NetworkInfo requests information about the NeoFS network of which the remote server is a part.
|
// NetworkInfo requests information about the NeoFS network of which the remote server is a part.
|
||||||
//
|
//
|
||||||
// Any client's internal or transport errors are returned as `error`.
|
// Any client's internal or transport errors are returned as `error`.
|
||||||
|
@ -192,21 +174,19 @@ func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetwo
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
resp := r.(*v2netmap.NetworkInfoResponse)
|
resp := r.(*v2netmap.NetworkInfoResponse)
|
||||||
|
|
||||||
|
const fieldNetInfo = "network info"
|
||||||
|
|
||||||
netInfoV2 := resp.GetBody().GetNetworkInfo()
|
netInfoV2 := resp.GetBody().GetNetworkInfo()
|
||||||
if netInfoV2 == nil {
|
if netInfoV2 == nil {
|
||||||
cc.err = errors.New("missing network info in response body")
|
cc.err = newErrMissingResponseField(fieldNetInfo)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var netInfo netmap.NetworkInfo
|
cc.err = res.info.ReadFromV2(*netInfoV2)
|
||||||
|
|
||||||
cc.err = netInfo.ReadFromV2(*netInfoV2)
|
|
||||||
if cc.err != nil {
|
if cc.err != nil {
|
||||||
cc.err = fmt.Errorf("invalid network info: %w", cc.err)
|
cc.err = newErrInvalidResponseField(fieldNetInfo, cc.err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res.setInfo(&netInfo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
|
|
@ -93,18 +93,12 @@ func (x *PrmObjectDelete) WithXHeaders(hs ...string) {
|
||||||
type ResObjectDelete struct {
|
type ResObjectDelete struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
idTomb *v2refs.ObjectID
|
tomb oid.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadTombstoneID reads identifier of the created tombstone object.
|
// Tombstone returns identifier of the created tombstone object.
|
||||||
// Returns false if ID is missing (not read).
|
func (x ResObjectDelete) Tombstone() oid.ID {
|
||||||
func (x ResObjectDelete) ReadTombstoneID(dst *oid.ID) bool {
|
return x.tomb
|
||||||
if x.idTomb != nil {
|
|
||||||
_ = dst.ReadFromV2(*x.idTomb)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectDelete marks an object for deletion from the container using NeoFS API protocol.
|
// ObjectDelete marks an object for deletion from the container using NeoFS API protocol.
|
||||||
|
@ -167,7 +161,18 @@ func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObj
|
||||||
return rpcapi.DeleteObject(&c.c, &req, client.WithContext(ctx))
|
return rpcapi.DeleteObject(&c.c, &req, client.WithContext(ctx))
|
||||||
}
|
}
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
res.idTomb = r.(*v2object.DeleteResponse).GetBody().GetTombstone().GetObjectID()
|
const fieldTombstone = "tombstone"
|
||||||
|
|
||||||
|
idTombV2 := r.(*v2object.DeleteResponse).GetBody().GetTombstone().GetObjectID()
|
||||||
|
if idTombV2 == nil {
|
||||||
|
cc.err = newErrMissingResponseField(fieldTombstone)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.err = res.tomb.ReadFromV2(*idTombV2)
|
||||||
|
if cc.err != nil {
|
||||||
|
cc.err = newErrInvalidResponseField(fieldTombstone, cc.err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
|
|
@ -195,6 +195,9 @@ func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectH
|
||||||
}
|
}
|
||||||
cc.result = func(r responseV2) {
|
cc.result = func(r responseV2) {
|
||||||
res.checksums = r.(*v2object.GetRangeHashResponse).GetBody().GetHashList()
|
res.checksums = r.(*v2object.GetRangeHashResponse).GetBody().GetHashList()
|
||||||
|
if len(res.checksums) == 0 {
|
||||||
|
cc.err = newErrMissingResponseField("hash list")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process call
|
// process call
|
||||||
|
|
|
@ -32,20 +32,12 @@ func (x *PrmObjectPutInit) SetCopiesNumber(copiesNumber uint32) {
|
||||||
type ResObjectPut struct {
|
type ResObjectPut struct {
|
||||||
statusRes
|
statusRes
|
||||||
|
|
||||||
resp v2object.PutResponse
|
obj oid.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadStoredObjectID reads identifier of the saved object.
|
// StoredObjectID returns identifier of the saved object.
|
||||||
// Returns false if ID is missing (not read).
|
func (x ResObjectPut) StoredObjectID() oid.ID {
|
||||||
func (x *ResObjectPut) ReadStoredObjectID(id *oid.ID) bool {
|
return x.obj
|
||||||
idv2 := x.resp.GetBody().GetObjectID()
|
|
||||||
if idv2 == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = id.ReadFromV2(*idv2)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectWriter is designed to write one object to NeoFS system.
|
// ObjectWriter is designed to write one object to NeoFS system.
|
||||||
|
@ -216,13 +208,15 @@ func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (*Obje
|
||||||
var (
|
var (
|
||||||
res ResObjectPut
|
res ResObjectPut
|
||||||
w ObjectWriter
|
w ObjectWriter
|
||||||
|
|
||||||
|
resp v2object.PutResponse
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx, w.cancelCtxStream = context.WithCancel(ctx)
|
ctx, w.cancelCtxStream = context.WithCancel(ctx)
|
||||||
|
|
||||||
w.partInit.SetCopiesNumber(prm.copyNum)
|
w.partInit.SetCopiesNumber(prm.copyNum)
|
||||||
|
|
||||||
stream, err := rpcapi.PutObject(&c.c, &res.resp, client.WithContext(ctx))
|
stream, err := rpcapi.PutObject(&c.c, &resp, client.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("open stream: %w", err)
|
return nil, fmt.Errorf("open stream: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -242,11 +236,25 @@ func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (*Obje
|
||||||
c.initCallContext(&w.ctxCall)
|
c.initCallContext(&w.ctxCall)
|
||||||
w.ctxCall.req = &req
|
w.ctxCall.req = &req
|
||||||
w.ctxCall.statusRes = &res
|
w.ctxCall.statusRes = &res
|
||||||
w.ctxCall.resp = &res.resp
|
w.ctxCall.resp = &resp
|
||||||
w.ctxCall.wReq = func() error {
|
w.ctxCall.wReq = func() error {
|
||||||
return stream.Write(&req)
|
return stream.Write(&req)
|
||||||
}
|
}
|
||||||
w.ctxCall.closer = stream.Close
|
w.ctxCall.closer = stream.Close
|
||||||
|
w.ctxCall.result = func(r responseV2) {
|
||||||
|
const fieldID = "ID"
|
||||||
|
|
||||||
|
idV2 := r.(*v2object.PutResponse).GetBody().GetObjectID()
|
||||||
|
if idV2 == nil {
|
||||||
|
w.ctxCall.err = newErrMissingResponseField(fieldID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.ctxCall.err = res.obj.ReadFromV2(*idV2)
|
||||||
|
if w.ctxCall.err != nil {
|
||||||
|
w.ctxCall.err = newErrInvalidResponseField(fieldID, w.ctxCall.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &w, nil
|
return &w, nil
|
||||||
}
|
}
|
||||||
|
|
37
pool/pool.go
37
pool/pool.go
|
@ -289,7 +289,9 @@ func (c *clientWrapper) balanceGet(ctx context.Context, prm PrmBalanceGet) (*acc
|
||||||
return nil, fmt.Errorf("balance get on client: %w", err)
|
return nil, fmt.Errorf("balance get on client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.Amount(), nil
|
bal := res.Amount()
|
||||||
|
|
||||||
|
return &bal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerPut invokes sdkClient.ContainerPut parse response status to error and return result as is.
|
// containerPut invokes sdkClient.ContainerPut parse response status to error and return result as is.
|
||||||
|
@ -310,12 +312,14 @@ func (c *clientWrapper) containerPut(ctx context.Context, prm PrmContainerPut) (
|
||||||
prm.waitParams.setDefaults()
|
prm.waitParams.setDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
err = waitForContainerPresence(ctx, c, res.ID(), &prm.waitParams)
|
idCnr := res.ID()
|
||||||
|
|
||||||
|
err = waitForContainerPresence(ctx, c, idCnr, &prm.waitParams)
|
||||||
if err = c.handleError(nil, err); err != nil {
|
if err = c.handleError(nil, err); err != nil {
|
||||||
return nil, fmt.Errorf("wait container presence on client: %w", err)
|
return nil, fmt.Errorf("wait container presence on client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.ID(), nil
|
return &idCnr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerGet invokes sdkClient.ContainerGet parse response status to error and return result as is.
|
// containerGet invokes sdkClient.ContainerGet parse response status to error and return result as is.
|
||||||
|
@ -400,7 +404,10 @@ func (c *clientWrapper) containerEACL(ctx context.Context, prm PrmContainerEACL)
|
||||||
if err = c.handleError(st, err); err != nil {
|
if err = c.handleError(st, err); err != nil {
|
||||||
return nil, fmt.Errorf("get eacl on client: %w", err)
|
return nil, fmt.Errorf("get eacl on client: %w", err)
|
||||||
}
|
}
|
||||||
return res.Table(), nil
|
|
||||||
|
eACL := res.Table()
|
||||||
|
|
||||||
|
return &eACL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerSetEACL invokes sdkClient.ContainerSetEACL parse response status to error.
|
// containerSetEACL invokes sdkClient.ContainerSetEACL parse response status to error.
|
||||||
|
@ -454,7 +461,10 @@ func (c *clientWrapper) endpointInfo(ctx context.Context, _ prmEndpointInfo) (*n
|
||||||
if err = c.handleError(st, err); err != nil {
|
if err = c.handleError(st, err); err != nil {
|
||||||
return nil, fmt.Errorf("endpoint info on client: %w", err)
|
return nil, fmt.Errorf("endpoint info on client: %w", err)
|
||||||
}
|
}
|
||||||
return res.NodeInfo(), nil
|
|
||||||
|
nodeInfo := res.NodeInfo()
|
||||||
|
|
||||||
|
return &nodeInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// networkInfo invokes sdkClient.NetworkInfo parse response status to error and return result as is.
|
// networkInfo invokes sdkClient.NetworkInfo parse response status to error and return result as is.
|
||||||
|
@ -470,7 +480,10 @@ func (c *clientWrapper) networkInfo(ctx context.Context, _ prmNetworkInfo) (*net
|
||||||
if err = c.handleError(st, err); err != nil {
|
if err = c.handleError(st, err); err != nil {
|
||||||
return nil, fmt.Errorf("network info on client: %w", err)
|
return nil, fmt.Errorf("network info on client: %w", err)
|
||||||
}
|
}
|
||||||
return res.Info(), nil
|
|
||||||
|
netInfo := res.Info()
|
||||||
|
|
||||||
|
return &netInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// objectPut writes object to NeoFS.
|
// objectPut writes object to NeoFS.
|
||||||
|
@ -551,11 +564,7 @@ func (c *clientWrapper) objectPut(ctx context.Context, prm PrmObjectPut) (*oid.I
|
||||||
return nil, fmt.Errorf("client failure: %w", err)
|
return nil, fmt.Errorf("client failure: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var id oid.ID
|
id := res.StoredObjectID()
|
||||||
|
|
||||||
if !res.ReadStoredObjectID(&id) {
|
|
||||||
return nil, errors.New("missing ID of the stored object")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &id, nil
|
return &id, nil
|
||||||
}
|
}
|
||||||
|
@ -2167,11 +2176,9 @@ func (p Pool) Statistic() Statistic {
|
||||||
}
|
}
|
||||||
|
|
||||||
// waitForContainerPresence waits until the container is found on the NeoFS network.
|
// waitForContainerPresence waits until the container is found on the NeoFS network.
|
||||||
func waitForContainerPresence(ctx context.Context, cli client, cnrID *cid.ID, waitParams *WaitParams) error {
|
func waitForContainerPresence(ctx context.Context, cli client, cnrID cid.ID, waitParams *WaitParams) error {
|
||||||
var prm PrmContainerGet
|
var prm PrmContainerGet
|
||||||
if cnrID != nil {
|
prm.SetContainerID(cnrID)
|
||||||
prm.SetContainerID(*cnrID)
|
|
||||||
}
|
|
||||||
|
|
||||||
return waitFor(ctx, waitParams, func(ctx context.Context) bool {
|
return waitFor(ctx, waitParams, func(ctx context.Context) bool {
|
||||||
_, err := cli.containerGet(ctx, prm)
|
_, err := cli.containerGet(ctx, prm)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
|
||||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||||
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
||||||
|
@ -479,7 +480,9 @@ func TestWaitPresence(t *testing.T) {
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err := waitForContainerPresence(ctx, mockCli, nil, &WaitParams{
|
var idCnr cid.ID
|
||||||
|
|
||||||
|
err := waitForContainerPresence(ctx, mockCli, idCnr, &WaitParams{
|
||||||
timeout: 120 * time.Second,
|
timeout: 120 * time.Second,
|
||||||
pollInterval: 5 * time.Second,
|
pollInterval: 5 * time.Second,
|
||||||
})
|
})
|
||||||
|
@ -489,7 +492,8 @@ func TestWaitPresence(t *testing.T) {
|
||||||
|
|
||||||
t.Run("context deadline exceeded", func(t *testing.T) {
|
t.Run("context deadline exceeded", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := waitForContainerPresence(ctx, mockCli, nil, &WaitParams{
|
var idCnr cid.ID
|
||||||
|
err := waitForContainerPresence(ctx, mockCli, idCnr, &WaitParams{
|
||||||
timeout: 500 * time.Millisecond,
|
timeout: 500 * time.Millisecond,
|
||||||
pollInterval: 5 * time.Second,
|
pollInterval: 5 * time.Second,
|
||||||
})
|
})
|
||||||
|
@ -499,7 +503,8 @@ func TestWaitPresence(t *testing.T) {
|
||||||
|
|
||||||
t.Run("ok", func(t *testing.T) {
|
t.Run("ok", func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := waitForContainerPresence(ctx, mockCli, nil, &WaitParams{
|
var idCnr cid.ID
|
||||||
|
err := waitForContainerPresence(ctx, mockCli, idCnr, &WaitParams{
|
||||||
timeout: 10 * time.Second,
|
timeout: 10 * time.Second,
|
||||||
pollInterval: 500 * time.Millisecond,
|
pollInterval: 500 * time.Millisecond,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue