From 28b49419abc0940a3c340a94babedfbd22cb02ba Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 15 Feb 2022 08:36:47 +0300 Subject: [PATCH] [#131] client: Re-implement Object Delete and Hash methods Also remove unused methods of `pool.Client` and `pool.Pool`. Signed-off-by: Leonard Lyubich --- client/object_delete.go | 134 ++++++++++++++++++++++++++++++ client/object_hash.go | 178 ++++++++++++++++++++++++++++++++++++++++ pool/mock_test.go | 129 +++-------------------------- pool/pool.go | 134 ++++++------------------------ 4 files changed, 347 insertions(+), 228 deletions(-) create mode 100644 client/object_delete.go create mode 100644 client/object_hash.go diff --git a/client/object_delete.go b/client/object_delete.go new file mode 100644 index 0000000..2ced50f --- /dev/null +++ b/client/object_delete.go @@ -0,0 +1,134 @@ +package client + +import ( + "context" + + v2object "github.com/nspcc-dev/neofs-api-go/v2/object" + v2refs "github.com/nspcc-dev/neofs-api-go/v2/refs" + rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc" + "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" + v2session "github.com/nspcc-dev/neofs-api-go/v2/session" + cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/nspcc-dev/neofs-sdk-go/session" + "github.com/nspcc-dev/neofs-sdk-go/token" +) + +// PrmObjectDelete groups parameters of ObjectDelete operation. +type PrmObjectDelete struct { + meta v2session.RequestMetaHeader + + body v2object.DeleteRequestBody + + addr v2refs.Address +} + +// WithinSession specifies session within which object should be read. +// +// Creator of the session acquires the authorship of the request. +// This may affect the execution of an operation (e.g. access control). +// +// Must be signed. +func (x *PrmObjectDelete) WithinSession(t session.Token) { + x.meta.SetSessionToken(t.ToV2()) +} + +// WithBearerToken attaches bearer token to be used for the operation. +// +// If set, underlying eACL rules will be used in access control. +// +// Must be signed. +func (x *PrmObjectDelete) WithBearerToken(t token.BearerToken) { + x.meta.SetBearerToken(t.ToV2()) +} + +// FromContainer specifies NeoFS container of the object. +// Required parameter. +func (x *PrmObjectDelete) FromContainer(id cid.ID) { + x.addr.SetContainerID(id.ToV2()) +} + +// ByID specifies identifier of the requested object. +// Required parameter. +func (x *PrmObjectDelete) ByID(id oid.ID) { + x.addr.SetObjectID(id.ToV2()) +} + +// ResObjectDelete groups resulting values of ObjectDelete operation. +type ResObjectDelete struct { + statusRes + + idTomb *v2refs.ObjectID +} + +// ReadTombstoneID reads identifier of the created tombstone object. +// Returns false if ID is missing (not read). +func (x ResObjectDelete) ReadTombstoneID(dst *oid.ID) bool { + if x.idTomb != nil { + *dst = *oid.NewIDFromV2(x.idTomb) // need smth better + return true + } + + return false +} + +// ObjectDelete marks an object for deletion from the container using NeoFS API protocol. +// As a marker, a special unit called a tombstone is placed in the container. +// It confirms the user's intent to delete the object, and is itself a container object. +// Explicit deletion is done asynchronously, and is generally not guaranteed. +// +// Returns a list of checksums in raw form: the format of hashes and their number +// is left for the caller to check. Client preserves the order of the server's response. +// +// Exactly one return value is non-nil. By default, server status is returned in res structure. +// Any client's internal or transport errors are returned as `error`, +// If WithNeoFSErrorParsing option has been provided, unsuccessful +// NeoFS status codes are returned as `error`, otherwise, are included +// in the returned result structure. +// +// Immediately panics if parameters are set incorrectly (see PrmObjectHash docs). +// Context is required and must not be nil. It is used for network communication. +// +// Return statuses: +// - global (see Client docs). +func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObjectDelete, error) { + switch { + case ctx == nil: + panic(panicMsgMissingContext) + case prm.addr.GetContainerID() == nil: + panic(panicMsgMissingContainer) + case prm.addr.GetObjectID() == nil: + panic("missing object") + } + + // form request body + prm.body.SetAddress(&prm.addr) + + // form request + var req v2object.DeleteRequest + req.SetBody(&prm.body) + req.SetMetaHeader(&prm.meta) + + // init call context + var ( + cc contextCall + res ResObjectDelete + ) + + c.initCallContext(&cc) + cc.req = &req + cc.statusRes = &res + cc.call = func() (responseV2, error) { + return rpcapi.DeleteObject(c.Raw(), &req, client.WithContext(ctx)) + } + cc.result = func(r responseV2) { + res.idTomb = r.(*v2object.DeleteResponse).GetBody().GetTombstone().GetObjectID() + } + + // process call + if !cc.processCall() { + return nil, cc.err + } + + return &res, nil +} diff --git a/client/object_hash.go b/client/object_hash.go new file mode 100644 index 0000000..ea8e311 --- /dev/null +++ b/client/object_hash.go @@ -0,0 +1,178 @@ +package client + +import ( + "context" + + v2object "github.com/nspcc-dev/neofs-api-go/v2/object" + v2refs "github.com/nspcc-dev/neofs-api-go/v2/refs" + rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc" + "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" + v2session "github.com/nspcc-dev/neofs-api-go/v2/session" + cid "github.com/nspcc-dev/neofs-sdk-go/container/id" + oid "github.com/nspcc-dev/neofs-sdk-go/object/id" + "github.com/nspcc-dev/neofs-sdk-go/session" + "github.com/nspcc-dev/neofs-sdk-go/token" +) + +// PrmObjectHash groups parameters of ObjectHash operation. +type PrmObjectHash struct { + meta v2session.RequestMetaHeader + + body v2object.GetRangeHashRequestBody + + tillichZemor bool + + addr v2refs.Address +} + +// MarkLocal tells the server to execute the operation locally. +func (x *PrmObjectHash) MarkLocal() { + x.meta.SetTTL(1) +} + +// WithinSession specifies session within which object should be read. +// +// Creator of the session acquires the authorship of the request. +// This may affect the execution of an operation (e.g. access control). +// +// Must be signed. +func (x *PrmObjectHash) WithinSession(t session.Token) { + x.meta.SetSessionToken(t.ToV2()) +} + +// WithBearerToken attaches bearer token to be used for the operation. +// +// If set, underlying eACL rules will be used in access control. +// +// Must be signed. +func (x *PrmObjectHash) WithBearerToken(t token.BearerToken) { + x.meta.SetBearerToken(t.ToV2()) +} + +// FromContainer specifies NeoFS container of the object. +// Required parameter. +func (x *PrmObjectHash) FromContainer(id cid.ID) { + x.addr.SetContainerID(id.ToV2()) +} + +// ByID specifies identifier of the requested object. +// Required parameter. +func (x *PrmObjectHash) ByID(id oid.ID) { + x.addr.SetObjectID(id.ToV2()) +} + +// SetRangeList sets list of ranges in (offset, length) pair format. +// Required parameter. +// +// If passed as slice, then it must not be mutated before the operation completes. +func (x *PrmObjectHash) SetRangeList(r ...uint64) { + ln := len(r) + if ln%2 != 0 { + panic("odd number of range parameters") + } + + rs := make([]*v2object.Range, ln/2) + + for i := 0; i < ln/2; i++ { + rs[i] = new(v2object.Range) + rs[i].SetOffset(r[2*i]) + rs[i].SetOffset(r[2*i+1]) + } + + x.body.SetRanges(rs) +} + +// TillichZemorAlgo changes the hash function to Tillich-Zemor +// (https://link.springer.com/content/pdf/10.1007/3-540-48658-5_5.pdf). +// +// By default, SHA256 hash function is used. +func (x *PrmObjectHash) TillichZemorAlgo() { + x.tillichZemor = true +} + +// UseSalt sets the salt to XOR the data range before hashing. +// +// Must not be mutated before the operation completes. +func (x *PrmObjectHash) UseSalt(salt []byte) { + x.body.SetSalt(salt) +} + +// ResObjectHash groups resulting values of ObjectHash operation. +type ResObjectHash struct { + statusRes + + checksums [][]byte +} + +// Checksums returns a list of calculated checksums in range order. +func (x ResObjectHash) Checksums() [][]byte { + return x.checksums +} + +// ObjectHash requests checksum of the range list of the object payload using +// NeoFS API protocol. +// +// Returns a list of checksums in raw form: the format of hashes and their number +// is left for the caller to check. Client preserves the order of the server's response. +// +// Exactly one return value is non-nil. By default, server status is returned in res structure. +// Any client's internal or transport errors are returned as `error`, +// If WithNeoFSErrorParsing option has been provided, unsuccessful +// NeoFS status codes are returned as `error`, otherwise, are included +// in the returned result structure. +// +// Immediately panics if parameters are set incorrectly (see PrmObjectHash docs). +// Context is required and must not be nil. It is used for network communication. +// +// Return statuses: +// - global (see Client docs). +func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectHash, error) { + switch { + case ctx == nil: + panic(panicMsgMissingContext) + case prm.addr.GetContainerID() == nil: + panic(panicMsgMissingContainer) + case prm.addr.GetObjectID() == nil: + panic("missing object") + case len(prm.body.GetRanges()) == 0: + panic("missing ranges") + } + + // form request body + prm.body.SetAddress(&prm.addr) + // ranges and salt are already by prm setters + + if prm.tillichZemor { + prm.body.SetType(v2refs.TillichZemor) + } else { + prm.body.SetType(v2refs.SHA256) + } + + // form request + var req v2object.GetRangeHashRequest + req.SetBody(&prm.body) + req.SetMetaHeader(&prm.meta) + + // init call context + var ( + cc contextCall + res ResObjectHash + ) + + c.initCallContext(&cc) + cc.req = &req + cc.statusRes = &res + cc.call = func() (responseV2, error) { + return rpcapi.HashObjectRange(c.Raw(), &req, client.WithContext(ctx)) + } + cc.result = func(r responseV2) { + res.checksums = r.(*v2object.GetRangeHashResponse).GetBody().GetHashList() + } + + // process call + if !cc.processCall() { + return nil, cc.err + } + + return &res, nil +} diff --git a/pool/mock_test.go b/pool/mock_test.go index c91c623..6c063a7 100644 --- a/pool/mock_test.go +++ b/pool/mock_test.go @@ -6,11 +6,9 @@ package pool import ( context "context" - io "io" reflect "reflect" gomock "github.com/golang/mock/gomock" - client "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" client0 "github.com/nspcc-dev/neofs-sdk-go/client" ) @@ -37,71 +35,6 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } -// AnnounceContainerUsedSpace mocks base method. -func (m *MockClient) AnnounceContainerUsedSpace(arg0 context.Context, arg1 client0.AnnounceSpacePrm) (*client0.AnnounceSpaceRes, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - ret := m.ctrl.Call(m, "AnnounceContainerUsedSpace", varargs...) - ret0, _ := ret[0].(*client0.AnnounceSpaceRes) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AnnounceContainerUsedSpace indicates an expected call of AnnounceContainerUsedSpace. -func (mr *MockClientMockRecorder) AnnounceContainerUsedSpace(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnnounceContainerUsedSpace", reflect.TypeOf((*MockClient)(nil).AnnounceContainerUsedSpace), varargs...) -} - -// AnnounceIntermediateTrust mocks base method. -func (m *MockClient) AnnounceIntermediateTrust(arg0 context.Context, arg1 client0.AnnounceIntermediateTrustPrm) (*client0.AnnounceIntermediateTrustRes, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - ret := m.ctrl.Call(m, "AnnounceIntermediateTrust", varargs...) - ret0, _ := ret[0].(*client0.AnnounceIntermediateTrustRes) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AnnounceIntermediateTrust indicates an expected call of AnnounceIntermediateTrust. -func (mr *MockClientMockRecorder) AnnounceIntermediateTrust(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnnounceIntermediateTrust", reflect.TypeOf((*MockClient)(nil).AnnounceIntermediateTrust), varargs...) -} - -// AnnounceLocalTrust mocks base method. -func (m *MockClient) AnnounceLocalTrust(arg0 context.Context, arg1 client0.AnnounceLocalTrustPrm) (*client0.AnnounceLocalTrustRes, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - ret := m.ctrl.Call(m, "AnnounceLocalTrust", varargs...) - ret0, _ := ret[0].(*client0.AnnounceLocalTrustRes) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AnnounceLocalTrust indicates an expected call of AnnounceLocalTrust. -func (mr *MockClientMockRecorder) AnnounceLocalTrust(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnnounceLocalTrust", reflect.TypeOf((*MockClient)(nil).AnnounceLocalTrust), varargs...) -} - -// Conn mocks base method. -func (m *MockClient) Conn() io.Closer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Conn") - ret0, _ := ret[0].(io.Closer) - return ret0 -} - -// Conn indicates an expected call of Conn. -func (mr *MockClientMockRecorder) Conn() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Conn", reflect.TypeOf((*MockClient)(nil).Conn)) -} - // CreateSession mocks base method. func (m *MockClient) CreateSession(arg0 context.Context, arg1 client0.CreateSessionPrm) (*client0.CreateSessionRes, error) { m.ctrl.T.Helper() @@ -136,15 +69,11 @@ func (mr *MockClientMockRecorder) DeleteContainer(arg0, arg1 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteContainer", reflect.TypeOf((*MockClient)(nil).DeleteContainer), varargs...) } -// DeleteObject mocks base method. -func (m *MockClient) DeleteObject(arg0 context.Context, arg1 *client0.DeleteObjectParams, arg2 ...client0.CallOption) (*client0.ObjectDeleteRes, error) { +// ObjectDelete mocks base method. +func (m *MockClient) ObjectDelete(arg0 context.Context, arg1 client0.PrmObjectDelete) (*client0.ResObjectDelete, error) { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteObject", varargs...) - ret0, _ := ret[0].(*client0.ObjectDeleteRes) + ret := m.ctrl.Call(m, "ObjectDelete", arg0, arg1) + ret0, _ := ret[0].(*client0.ResObjectDelete) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -153,7 +82,7 @@ func (m *MockClient) DeleteObject(arg0 context.Context, arg1 *client0.DeleteObje func (mr *MockClientMockRecorder) DeleteObject(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObject", reflect.TypeOf((*MockClient)(nil).DeleteObject), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObject", reflect.TypeOf((*MockClient)(nil).ObjectDelete), varargs...) } // EACL mocks base method. @@ -240,26 +169,6 @@ func (mr *MockClientMockRecorder) GetObject(arg0, arg1 interface{}, arg2 ...inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObjectGetInit", reflect.TypeOf((*MockClient)(nil).ObjectGetInit), varargs...) } -// HashObjectPayloadRanges mocks base method. -func (m *MockClient) HashObjectPayloadRanges(arg0 context.Context, arg1 *client0.RangeChecksumParams, arg2 ...client0.CallOption) (*client0.ObjectRangeHashRes, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "HashObjectPayloadRanges", varargs...) - ret0, _ := ret[0].(*client0.ObjectRangeHashRes) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// HashObjectPayloadRanges indicates an expected call of HashObjectPayloadRanges. -func (mr *MockClientMockRecorder) HashObjectPayloadRanges(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HashObjectPayloadRanges", reflect.TypeOf((*MockClient)(nil).HashObjectPayloadRanges), varargs...) -} - // ObjectHead mocks base method. func (m *MockClient) ObjectHead(arg0 context.Context, arg1 client0.PrmObjectHead) (*client0.ResObjectHead, error) { m.ctrl.T.Helper() @@ -359,29 +268,11 @@ func (mr *MockClientMockRecorder) PutObject(arg0, arg1 interface{}) *gomock.Call return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ObjectPutInit", reflect.TypeOf((*MockClient)(nil).ObjectPutInit), varargs...) } -// Raw mocks base method. -func (m *MockClient) Raw() *client.Client { +// ObjectSearchInitmocks base method. +func (m *MockClient) ObjectSearchInit(arg0 context.Context, arg1 client0.PrmObjectSearch) (*client0.ObjectListReader, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Raw") - ret0, _ := ret[0].(*client.Client) - return ret0 -} - -// Raw indicates an expected call of Raw. -func (mr *MockClientMockRecorder) Raw() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Raw", reflect.TypeOf((*MockClient)(nil).Raw)) -} - -// SearchObjects mocks base method. -func (m *MockClient) SearchObjects(arg0 context.Context, arg1 *client0.SearchObjectParams, arg2 ...client0.CallOption) (*client0.ObjectSearchRes, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "SearchObjects", varargs...) - ret0, _ := ret[0].(*client0.ObjectSearchRes) + ret := m.ctrl.Call(m, "ObjectSearchInit", arg0, arg1) + ret0, _ := ret[0].(*client0.ObjectListReader) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -390,7 +281,7 @@ func (m *MockClient) SearchObjects(arg0 context.Context, arg1 *client0.SearchObj func (mr *MockClientMockRecorder) SearchObjects(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchObjects", reflect.TypeOf((*MockClient)(nil).SearchObjects), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchObjects", reflect.TypeOf((*MockClient)(nil).ObjectSearchInit), varargs...) } // SetEACL mocks base method. diff --git a/pool/pool.go b/pool/pool.go index 41e2c28..ee6ff7f 100644 --- a/pool/pool.go +++ b/pool/pool.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "crypto/ecdsa" - "crypto/sha256" "errors" "fmt" "io" @@ -16,7 +15,6 @@ import ( "time" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" - apiclient "github.com/nspcc-dev/neofs-api-go/v2/rpc/client" "github.com/nspcc-dev/neofs-sdk-go/accounting" "github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/container" @@ -40,23 +38,15 @@ type Client interface { DeleteContainer(context.Context, client.ContainerDeletePrm) (*client.ContainerDeleteRes, error) EACL(context.Context, client.EACLPrm) (*client.EACLRes, error) SetEACL(context.Context, client.SetEACLPrm) (*client.SetEACLRes, error) - AnnounceContainerUsedSpace(context.Context, client.AnnounceSpacePrm) (*client.AnnounceSpaceRes, error) EndpointInfo(context.Context, client.EndpointInfoPrm) (*client.EndpointInfoRes, error) NetworkInfo(context.Context, client.NetworkInfoPrm) (*client.NetworkInfoRes, error) ObjectPutInit(context.Context, client.PrmObjectPutInit) (*client.ObjectWriter, error) - DeleteObject(context.Context, *client.DeleteObjectParams, ...client.CallOption) (*client.ObjectDeleteRes, error) + ObjectDelete(context.Context, client.PrmObjectDelete) (*client.ResObjectDelete, error) ObjectGetInit(context.Context, client.PrmObjectGet) (*client.ObjectReader, error) ObjectHead(context.Context, client.PrmObjectHead) (*client.ResObjectHead, error) ObjectRangeInit(context.Context, client.PrmObjectRange) (*client.ObjectRangeReader, error) - HashObjectPayloadRanges(context.Context, *client.RangeChecksumParams, ...client.CallOption) (*client.ObjectRangeHashRes, error) ObjectSearchInit(context.Context, client.PrmObjectSearch) (*client.ObjectListReader, error) - AnnounceLocalTrust(context.Context, client.AnnounceLocalTrustPrm) (*client.AnnounceLocalTrustRes, error) - AnnounceIntermediateTrust(context.Context, client.AnnounceIntermediateTrustPrm) (*client.AnnounceIntermediateTrustRes, error) CreateSession(context.Context, client.CreateSessionPrm) (*client.CreateSessionRes, error) - - Raw() *apiclient.Client - - Conn() io.Closer } // BuilderOptions contains options used to build connection pool. @@ -162,12 +152,10 @@ type Pool interface { type Object interface { PutObject(ctx context.Context, hdr object.Object, payload io.Reader, opts ...CallOption) (*oid.ID, error) - DeleteObject(ctx context.Context, params *client.DeleteObjectParams, opts ...CallOption) error + DeleteObject(ctx context.Context, addr address.Address, opts ...CallOption) error GetObject(context.Context, address.Address, ...CallOption) (*ResGetObject, error) HeadObject(context.Context, address.Address, ...CallOption) (*object.Object, error) ObjectRange(ctx context.Context, addr address.Address, off, ln uint64, opts ...CallOption) (*ResObjectRange, error) - ObjectPayloadRangeSHA256(ctx context.Context, params *client.RangeChecksumParams, opts ...CallOption) ([][32]byte, error) - ObjectPayloadRangeTZ(ctx context.Context, params *client.RangeChecksumParams, opts ...CallOption) ([][64]byte, error) SearchObjects(context.Context, cid.ID, object.SearchFilters, ...CallOption) (*ResObjectSearch, error) } @@ -817,23 +805,37 @@ func (p *pool) PutObject(ctx context.Context, hdr object.Object, payload io.Read return &id, nil } -func (p *pool) DeleteObject(ctx context.Context, params *client.DeleteObjectParams, opts ...CallOption) error { +func (p *pool) DeleteObject(ctx context.Context, addr address.Address, opts ...CallOption) error { cfg := cfgFromOpts(append(opts, useDefaultSession())...) - cp, options, err := p.conn(ctx, cfg) + + var prm client.PrmObjectDelete + + var cc callContextWithRetry + + cc.Context = ctx + cc.sessionTarget = prm.WithinSession + + err := p.initCallContextWithRetry(&cc, cfg) if err != nil { return err } - _, err = cp.client.DeleteObject(ctx, params, options...) - - if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry { - opts = append(opts, retry()) - return p.DeleteObject(ctx, params, opts...) + if cnr := addr.ContainerID(); cnr != nil { + prm.FromContainer(*cnr) } - // here err already carries both status and client errors + if obj := addr.ObjectID(); obj != nil { + prm.ByID(*obj) + } - return err + return p.callWithRetry(&cc, func() error { + _, err := cc.client.ObjectDelete(ctx, prm) + if err != nil { + return fmt.Errorf("remove object via client: %w", err) + } + + return nil + }) } type objectReadCloser client.ObjectReader @@ -1006,92 +1008,6 @@ func (p *pool) ObjectRange(ctx context.Context, addr address.Address, off, ln ui return &res, nil } -func copyRangeChecksumParams(prm *client.RangeChecksumParams) *client.RangeChecksumParams { - var prmCopy client.RangeChecksumParams - - prmCopy.WithAddress(prm.Address()) - prmCopy.WithSalt(prm.Salt()) - prmCopy.WithRangeList(prm.RangeList()...) - - return &prmCopy -} - -func (p *pool) ObjectPayloadRangeSHA256(ctx context.Context, params *client.RangeChecksumParams, opts ...CallOption) ([][32]byte, error) { - cfg := cfgFromOpts(append(opts, useDefaultSession())...) - cp, options, err := p.conn(ctx, cfg) - if err != nil { - return nil, err - } - - // FIXME: pretty bad approach but we should not mutate params through the pointer - // If non-SHA256 algo is set then we need to reset it. - params = copyRangeChecksumParams(params) - // SHA256 by default, no need to do smth - - res, err := cp.client.HashObjectPayloadRanges(ctx, params, options...) - - if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry { - opts = append(opts, retry()) - return p.ObjectPayloadRangeSHA256(ctx, params, opts...) - } - - if err != nil { // here err already carries both status and client errors - return nil, err - } - - cliHashes := res.Hashes() - - hs := make([][sha256.Size]byte, len(cliHashes)) - - for i := range cliHashes { - if ln := len(cliHashes[i]); ln != sha256.Size { - return nil, fmt.Errorf("invalid SHA256 checksum size %d", ln) - } - - copy(hs[i][:], cliHashes[i]) - } - - return hs, nil -} - -func (p *pool) ObjectPayloadRangeTZ(ctx context.Context, params *client.RangeChecksumParams, opts ...CallOption) ([][64]byte, error) { - cfg := cfgFromOpts(append(opts, useDefaultSession())...) - cp, options, err := p.conn(ctx, cfg) - if err != nil { - return nil, err - } - - // FIXME: pretty bad approach but we should not mutate params through the pointer - // We need to set Tillich-Zemor algo. - params = copyRangeChecksumParams(params) - params.TZ() - - res, err := cp.client.HashObjectPayloadRanges(ctx, params, options...) - - if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry { - opts = append(opts, retry()) - return p.ObjectPayloadRangeTZ(ctx, params, opts...) - } - - if err != nil { // here err already carries both status and client errors - return nil, err - } - - cliHashes := res.Hashes() - - hs := make([][client.TZSize]byte, len(cliHashes)) - - for i := range cliHashes { - if ln := len(cliHashes[i]); ln != client.TZSize { - return nil, fmt.Errorf("invalid TZ checksum size %d", ln) - } - - copy(hs[i][:], cliHashes[i]) - } - - return hs, nil -} - type ResObjectSearch struct { r *client.ObjectListReader }