[#92] client: Accept structured parameters in non-object operations

Define `XPrm` type for each `X` client operation which structures
parameters. Export setters of each parameterized value. Emphasize that
some parameters are required. Make the client panic when the parameters
are incorrectly set. Get rid of vadiadic call options and `CallOption`
type. Improve documentation of client behavior.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-12-02 15:21:54 +03:00 committed by Alex Vanin
parent 596774ce5b
commit 213d20e3fb
13 changed files with 1100 additions and 885 deletions

View file

@ -2,82 +2,99 @@ package client
import (
"context"
"fmt"
v2accounting "github.com/nspcc-dev/neofs-api-go/v2/accounting"
rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc"
"github.com/nspcc-dev/neofs-api-go/v2/rpc/client"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/accounting"
"github.com/nspcc-dev/neofs-sdk-go/owner"
)
type BalanceOfRes struct {
// GetBalancePrm groups parameters of GetBalance operation.
type GetBalancePrm struct {
ownerSet bool
ownerID owner.ID
}
// SetAccount sets identifier of the NeoFS account for which the balance is requested.
// Required parameter. Must be a valid ID according to NeoFS API protocol.
func (x *GetBalancePrm) SetAccount(id owner.ID) {
x.ownerID = id
x.ownerSet = true
}
// GetBalanceRes groups resulting values of GetBalance operation.
type GetBalanceRes struct {
statusRes
amount *accounting.Decimal
}
func (x *BalanceOfRes) setAmount(v *accounting.Decimal) {
func (x *GetBalanceRes) setAmount(v *accounting.Decimal) {
x.amount = v
}
func (x BalanceOfRes) Amount() *accounting.Decimal {
// Amount returns current amount of funds on the NeoFS account as decimal number.
//
// Client doesn't retain value so modification is safe.
func (x GetBalanceRes) Amount() *accounting.Decimal {
return x.amount
}
// GetBalance receives owner balance through NeoFS API call.
// GetBalance requests current balance of the NeoFS account.
//
// 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.
func (c *Client) GetBalance(ctx context.Context, owner *owner.ID, opts ...CallOption) (*BalanceOfRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see GetBalancePrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in GetBalanceRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) GetBalance(ctx context.Context, prm GetBalancePrm) (*GetBalanceRes, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.ownerSet:
panic("account not set")
case !prm.ownerID.Valid():
panic("invalid account ID")
}
reqBody := new(v2accounting.BalanceRequestBody)
reqBody.SetOwnerID(owner.ToV2())
// form request body
var body v2accounting.BalanceRequestBody
req := new(v2accounting.BalanceRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
body.SetOwnerID(prm.ownerID.ToV2())
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
// form request
var req v2accounting.BalanceRequest
resp, err := rpcapi.Balance(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
req.SetBody(&body)
// init call context
var (
res = new(BalanceOfRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res GetBalanceRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.Balance(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
}
cc.result = func(r responseV2) {
resp := r.(*v2accounting.BalanceResponse)
res.setAmount(accounting.NewDecimalFromV2(resp.GetBody().GetBalance()))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}

View file

@ -1,10 +1,14 @@
package client
import (
"crypto/ecdsa"
"fmt"
v2session "github.com/nspcc-dev/neofs-api-go/v2/session"
"github.com/nspcc-dev/neofs-api-go/v2/signature"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
// common interface of resulting structures with API status.
@ -87,3 +91,175 @@ func (c *Client) processResponseV2(res *processResponseV2Res, prm processRespons
return unsuccessfulStatus
}
type prmSession struct {
tokenSessionSet bool
tokenSession session.Token
}
// SetSessionToken sets token of the session within which request should be sent.
func (x *prmSession) SetSessionToken(tok session.Token) {
x.tokenSession = tok
x.tokenSessionSet = true
}
func (x prmSession) writeToMetaHeader(meta *v2session.RequestMetaHeader) {
if x.tokenSessionSet {
meta.SetSessionToken(x.tokenSession.ToV2())
}
}
// panic messages.
const (
panicMsgMissingContext = "missing context"
panicMsgMissingContainer = "missing container"
)
// groups all the details required to send a single request and process a response to it.
type contextCall struct {
// ==================================================
// state vars that do not require explicit initialization
// final error to be returned from client method
err error
// received response
resp responseV2
// ==================================================
// shared parameters which are set uniformly on all calls
// request signing key
key ecdsa.PrivateKey
// callback prior to processing the response by the client
callbackResp func(ResponseMetaInfo) error
// if set, protocol errors will be expanded into a final error
resolveAPIFailures bool
// NeoFS network magic
netMagic uint64
// ==================================================
// custom call parameters
// structure of the call result
statusRes resCommon
// request to be signed with a key and sent
req interface {
GetMetaHeader() *v2session.RequestMetaHeader
SetMetaHeader(*v2session.RequestMetaHeader)
}
// function to send a request (unary) and receive a response
call func() (responseV2, error)
// function of writing response fields to the resulting structure (optional)
result func(v2 responseV2)
}
func (x contextCall) prepareRequest() {
meta := x.req.GetMetaHeader()
if meta == nil {
meta = new(v2session.RequestMetaHeader)
x.req.SetMetaHeader(meta)
}
if meta.GetTTL() == 0 {
meta.SetTTL(2)
}
if meta.GetVersion() == nil {
meta.SetVersion(version.Current().ToV2())
}
meta.SetNetworkMagic(x.netMagic)
}
// performs common actions of response processing and writes any problem as a result status or client error
// (in both cases returns false).
//
// Actions:
// * verify signature (internal);
// * call response callback (internal);
// * unwrap status error (optional).
func (x *contextCall) processResponse() bool {
// call response callback if set
if x.callbackResp != nil {
x.err = x.callbackResp(ResponseMetaInfo{
key: x.resp.GetVerificationHeader().GetBodySignature().GetKey(),
})
if x.err != nil {
x.err = fmt.Errorf("response callback error: %w", x.err)
return false
}
}
// note that we call response callback before signature check since it is expected more lightweight
// while verification needs marshaling
// verify response signature
x.err = signature.VerifyServiceMessage(x.resp)
if x.err != nil {
x.err = fmt.Errorf("invalid response signature: %w", x.err)
return false
}
// get result status
st := apistatus.FromStatusV2(x.resp.GetMetaHeader().GetStatus())
// unwrap unsuccessful status and return it
// as error if client has been configured so
successfulStatus := apistatus.IsSuccessful(st)
if !successfulStatus && x.resolveAPIFailures {
x.err = apistatus.ErrFromStatus(st)
return false
}
x.statusRes.setStatus(st)
return successfulStatus
}
// goes through all stages of sending a request and processing a response. Returns true if successful.
func (x *contextCall) processCall() bool {
// prepare the request
x.prepareRequest()
// sign the request
x.err = signature.SignServiceMessage(&x.key, x.req)
if x.err != nil {
x.err = fmt.Errorf("sign request: %w", x.err)
return false
}
// perform RPC
x.resp, x.err = x.call()
if x.err != nil {
x.err = fmt.Errorf("transport error: %w", x.err)
return false
}
// process the response
ok := x.processResponse()
if !ok {
return false
}
// write response to resulting structure
if x.result != nil {
x.result(x.resp)
}
return true
}
// initializes static cross-call parameters inherited from client.
func (c *Client) initCallContext(ctx *contextCall) {
ctx.key = *c.opts.key
ctx.resolveAPIFailures = c.opts.parseNeoFSErrors
ctx.callbackResp = c.opts.cbRespInfo
ctx.netMagic = c.opts.netMagic
}

View file

@ -2,14 +2,13 @@ package client
import (
"context"
"fmt"
v2container "github.com/nspcc-dev/neofs-api-go/v2/container"
"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"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
"github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
@ -17,44 +16,35 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/signature"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
type delContainerSignWrapper struct {
body *v2container.DeleteRequestBody
// ContainerPutPrm groups parameters of PutContainer operation.
type ContainerPutPrm struct {
prmSession
cnrSet bool
cnr container.Container
}
// EACLWithSignature represents eACL table/signature pair.
type EACLWithSignature struct {
table *eacl.Table
}
func (c delContainerSignWrapper) ReadSignedData(bytes []byte) ([]byte, error) {
return c.body.GetContainerID().GetValue(), nil
}
func (c delContainerSignWrapper) SignedDataSize() int {
return len(c.body.GetContainerID().GetValue())
}
// EACL returns eACL table.
func (e EACLWithSignature) EACL() *eacl.Table {
return e.table
}
// Signature returns table signature.
//
// Deprecated: use EACL().Signature() instead.
func (e EACLWithSignature) Signature() *signature.Signature {
return e.table.Signature()
// SetContainer sets structured information about new NeoFS container.
// Required parameter.
func (x *ContainerPutPrm) SetContainer(cnr container.Container) {
x.cnr = cnr
x.cnrSet = true
}
// ContainerPutRes groups resulting values of PutContainer operation.
type ContainerPutRes struct {
statusRes
id *cid.ID
}
// 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
// asynchronously check if the save was successful).
//
// Client doesn't retain value so modification is safe.
func (x ContainerPutRes) ID() *cid.ID {
return x.id
}
@ -63,37 +53,42 @@ func (x *ContainerPutRes) setID(id *cid.ID) {
x.id = id
}
// PutContainer puts container through NeoFS API call.
// PutContainer sends request to save container in NeoFS.
//
// 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.
func (c *Client) PutContainer(ctx context.Context, cnr *container.Container, opts ...CallOption) (*ContainerPutRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see ContainerPutRes.ID).
//
// Immediately panics if parameters are set incorrectly (see ContainerPutPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ContainerPutRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) PutContainer(ctx context.Context, prm ContainerPutPrm) (*ContainerPutRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.cnrSet:
panic(panicMsgMissingContainer)
}
// set transport version
cnr.SetVersion(version.Current())
// if container owner is not set, then use client key as owner
if cnr.OwnerID() == nil {
ownerID := owner.NewIDFromPublicKey(&callOptions.key.PublicKey)
cnr.SetOwnerID(ownerID)
}
// TODO: check private key is set before forming the request
// form request body
reqBody := new(v2container.PutRequestBody)
reqBody.SetContainer(cnr.ToV2())
reqBody.SetContainer(prm.cnr.ToV2())
// sign container
signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetContainer()}
err := sigutil.SignDataWithHandler(callOptions.key, signWrapper, func(key []byte, sig []byte) {
err := sigutil.SignDataWithHandler(c.opts.key, signWrapper, func(key []byte, sig []byte) {
containerSignature := new(refs.Signature)
containerSignature.SetKey(key)
containerSignature.SetSign(sig)
@ -103,62 +98,66 @@ func (c *Client) PutContainer(ctx context.Context, cnr *container.Container, opt
return nil, err
}
req := new(v2container.PutRequest)
// form meta header
var meta v2session.RequestMetaHeader
prm.prmSession.writeToMetaHeader(&meta)
// form request
var req v2container.PutRequest
req.SetBody(reqBody)
req.SetMetaHeader(&meta)
meta := v2MetaHeaderFromOpts(callOptions)
meta.SetSessionToken(cnr.SessionToken().ToV2())
req.SetMetaHeader(meta)
err = v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.PutContainer(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, err
}
// init call context
var (
res = new(ContainerPutRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res ContainerPutRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.PutContainer(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
}
// sets result status
st := apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus())
res.setStatus(st)
if apistatus.IsSuccessful(st) {
cc.result = func(r responseV2) {
resp := r.(*v2container.PutResponse)
res.setID(cid.NewFromV2(resp.GetBody().GetContainerID()))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// ContainerGetPrm groups parameters of GetContainer operation.
type ContainerGetPrm struct {
idSet bool
id cid.ID
}
// SetContainer sets identifier of the container to be read.
// Required parameter.
func (x *ContainerGetPrm) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
// ContainerGetRes groups resulting values of GetContainer operation.
type ContainerGetRes struct {
statusRes
cnr *container.Container
}
// Container returns structured information about the requested container.
//
// Client doesn't retain value so modification is safe.
func (x ContainerGetRes) Container() *container.Container {
return x.cnr
}
@ -167,56 +166,50 @@ func (x *ContainerGetRes) setContainer(cnr *container.Container) {
x.cnr = cnr
}
// GetContainer receives container structure through NeoFS API call.
// GetContainer reads NeoFS container from by ID.
//
// 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.
func (c *Client) GetContainer(ctx context.Context, id *cid.ID, opts ...CallOption) (*ContainerGetRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see ContainerGetPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ContainerGetRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) GetContainer(ctx context.Context, prm ContainerGetPrm) (*ContainerGetRes, error) {
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.idSet:
panic(panicMsgMissingContainer)
}
// form request body
reqBody := new(v2container.GetRequestBody)
reqBody.SetContainerID(id.ToV2())
reqBody.SetContainerID(prm.id.ToV2())
// form request
var req v2container.GetRequest
req := new(v2container.GetRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.GetContainer(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(ContainerGetRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res ContainerGetRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
}
return res, nil
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.GetContainer(c.Raw(), &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.GetResponse)
body := resp.GetBody()
@ -231,78 +224,94 @@ func (c *Client) GetContainer(ctx context.Context, id *cid.ID, opts ...CallOptio
)
res.setContainer(cnr)
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// ContainerListPrm groups parameters of ListContainers operation.
type ContainerListPrm struct {
ownerSet bool
ownerID owner.ID
}
// SetAccount sets identifier of the NeoFS account to list the containers.
// Required parameter. Must be a valid ID according to NeoFS API protocol.
func (x *ContainerListPrm) SetAccount(id owner.ID) {
x.ownerID = id
x.ownerSet = true
}
// ContainerListRes groups resulting values of ListContainers operation.
type ContainerListRes struct {
statusRes
ids []*cid.ID
}
func (x ContainerListRes) IDList() []*cid.ID {
// Containers returns list of identifiers of the account-owned containers.
//
// Client doesn't retain value so modification is safe.
func (x ContainerListRes) Containers() []*cid.ID {
return x.ids
}
func (x *ContainerListRes) setIDList(ids []*cid.ID) {
func (x *ContainerListRes) setContainers(ids []*cid.ID) {
x.ids = ids
}
// ListContainers receives all owner's containers through NeoFS API call.
// ListContainers requests identifiers of the account-owned containers.
//
// 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.
func (c *Client) ListContainers(ctx context.Context, ownerID *owner.ID, opts ...CallOption) (*ContainerListRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
}
if ownerID == nil {
ownerID = owner.NewIDFromPublicKey(&callOptions.key.PublicKey)
//
// Immediately panics if parameters are set incorrectly (see ContainerListPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ContainerListRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) ListContainers(ctx context.Context, prm ContainerListPrm) (*ContainerListRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.ownerSet:
panic("account not set")
case !prm.ownerID.Valid():
panic("invalid account")
}
// form request body
reqBody := new(v2container.ListRequestBody)
reqBody.SetOwnerID(ownerID.ToV2())
reqBody.SetOwnerID(prm.ownerID.ToV2())
// form request
var req v2container.ListRequest
req := new(v2container.ListRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.ListContainers(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(ContainerListRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res ContainerListRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
}
return res, nil
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.ListContainers(c.Raw(), &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.ListResponse)
ids := make([]*cid.ID, 0, len(resp.GetBody().GetContainerIDs()))
@ -310,34 +319,82 @@ func (c *Client) ListContainers(ctx context.Context, ownerID *owner.ID, opts ...
ids = append(ids, cid.NewFromV2(cidV2))
}
res.setIDList(ids)
res.setContainers(ids)
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// ContainerDeletePrm groups parameters of DeleteContainer operation.
type ContainerDeletePrm struct {
prmSession
idSet bool
id cid.ID
}
// SetContainer sets identifier of the NeoFS container to be removed.
// Required parameter.
func (x *ContainerDeletePrm) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
// ContainerDeleteRes groups resulting values of DeleteContainer operation.
type ContainerDeleteRes struct {
statusRes
}
// DeleteContainer deletes specified container through NeoFS API call.
// implements github.com/nspcc-dev/neofs-sdk-go/util/signature.DataSource.
type delContainerSignWrapper struct {
body *v2container.DeleteRequestBody
}
func (c delContainerSignWrapper) ReadSignedData([]byte) ([]byte, error) {
return c.body.GetContainerID().GetValue(), nil
}
func (c delContainerSignWrapper) SignedDataSize() int {
return len(c.body.GetContainerID().GetValue())
}
// DeleteContainer sends request to remove the NeoFS container.
//
// 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.
func (c *Client) DeleteContainer(ctx context.Context, id *cid.ID, opts ...CallOption) (*ContainerDeleteRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see GetContainer).
//
// Immediately panics if parameters are set incorrectly (see ContainerDeletePrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ContainerDeleteRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) DeleteContainer(ctx context.Context, prm ContainerDeletePrm) (*ContainerDeleteRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.idSet:
panic(panicMsgMissingContainer)
}
// form request body
reqBody := new(v2container.DeleteRequestBody)
reqBody.SetContainerID(id.ToV2())
reqBody.SetContainerID(prm.id.ToV2())
// sign container
err := sigutil.SignDataWithHandler(callOptions.key,
err := sigutil.SignDataWithHandler(c.opts.key,
delContainerSignWrapper{
body: reqBody,
},
@ -352,107 +409,115 @@ func (c *Client) DeleteContainer(ctx context.Context, id *cid.ID, opts ...CallOp
return nil, err
}
req := new(v2container.DeleteRequest)
// form meta header
var meta v2session.RequestMetaHeader
prm.prmSession.writeToMetaHeader(&meta)
// form request
var req v2container.DeleteRequest
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
req.SetMetaHeader(&meta)
err = v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.DeleteContainer(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(ContainerDeleteRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res ContainerDeleteRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.DeleteContainer(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return res, nil
return &res, nil
}
// EACLPrm groups parameters of EACL operation.
type EACLPrm struct {
idSet bool
id cid.ID
}
// SetContainer sets identifier of the NeoFS container to read the eACL table.
// Required parameter.
func (x *EACLPrm) SetContainer(id cid.ID) {
x.id = id
x.idSet = true
}
// EACLRes groups resulting values of EACL operation.
type EACLRes struct {
statusRes
table *eacl.Table
}
// Table returns eACL table of the requested container.
//
// Client doesn't retain value so modification is safe.
func (x EACLRes) Table() *eacl.Table {
return x.table
}
func (x *EACLRes) SetTable(table *eacl.Table) {
func (x *EACLRes) setTable(table *eacl.Table) {
x.table = table
}
// EACL receives eACL of the specified container through NeoFS API call.
// EACL reads eACL table of the NeoFS container.
//
// 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.
func (c *Client) EACL(ctx context.Context, id *cid.ID, opts ...CallOption) (*EACLRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see EACLPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in EACLRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) EACL(ctx context.Context, prm EACLPrm) (*EACLRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.idSet:
panic(panicMsgMissingContainer)
}
// form request body
reqBody := new(v2container.GetExtendedACLRequestBody)
reqBody.SetContainerID(id.ToV2())
reqBody.SetContainerID(prm.id.ToV2())
// form request
var req v2container.GetExtendedACLRequest
req := new(v2container.GetExtendedACLRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.GetEACL(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(EACLRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res EACLRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
}
return res, nil
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.GetEACL(c.Raw(), &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2container.GetExtendedACLResponse)
body := resp.GetBody()
@ -466,35 +531,71 @@ func (c *Client) EACL(ctx context.Context, id *cid.ID, opts ...CallOption) (*EAC
signature.NewFromV2(body.GetSignature()),
)
res.SetTable(table)
res.setTable(table)
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// SetEACLPrm groups parameters of SetEACL operation.
type SetEACLPrm struct {
prmSession
tableSet bool
table eacl.Table
}
// SetTable sets eACL table structure to be set for the container.
// Required parameter.
func (x *SetEACLPrm) SetTable(table eacl.Table) {
x.table = table
x.tableSet = true
}
// SetEACLRes groups resulting values of SetEACL operation.
type SetEACLRes struct {
statusRes
}
// SetEACL sets eACL through NeoFS API call.
// SetEACL sends request to update eACL table of the NeoFS container.
//
// 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.
func (c *Client) SetEACL(ctx context.Context, eacl *eacl.Table, opts ...CallOption) (*SetEACLRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// Success can be verified by reading by identifier (see EACL).
//
// Immediately panics if parameters are set incorrectly (see SetEACLPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in ContainerDeleteRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) SetEACL(ctx context.Context, prm SetEACLPrm) (*SetEACLRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case !prm.tableSet:
panic("eACL table not set")
}
// form request body
reqBody := new(v2container.SetExtendedACLRequestBody)
reqBody.SetEACL(eacl.ToV2())
reqBody.SetEACL(prm.table.ToV2())
// sign the eACL table
signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetEACL()}
err := sigutil.SignDataWithHandler(callOptions.key, signWrapper, func(key []byte, sig []byte) {
err := sigutil.SignDataWithHandler(c.opts.key, signWrapper, func(key []byte, sig []byte) {
eaclSignature := new(refs.Signature)
eaclSignature.SetKey(key)
eaclSignature.SetSign(sig)
@ -504,113 +605,116 @@ func (c *Client) SetEACL(ctx context.Context, eacl *eacl.Table, opts ...CallOpti
return nil, err
}
req := new(v2container.SetExtendedACLRequest)
// form meta header
var meta v2session.RequestMetaHeader
prm.prmSession.writeToMetaHeader(&meta)
// form request
var req v2container.SetExtendedACLRequest
req.SetBody(reqBody)
req.SetMetaHeader(&meta)
meta := v2MetaHeaderFromOpts(callOptions)
meta.SetSessionToken(eacl.SessionToken().ToV2())
req.SetMetaHeader(meta)
err = v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.SetEACL(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(SetEACLRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res SetEACLRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.SetEACL(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return res, nil
return &res, nil
}
// AnnounceSpacePrm groups parameters of AnnounceContainerUsedSpace operation.
type AnnounceSpacePrm struct {
announcements []container.UsedSpaceAnnouncement
}
// SetValues sets values describing volume of space that is used for the container objects.
// Required parameter. Must not be empty.
//
// Must not be mutated before the end of the operation.
func (x *AnnounceSpacePrm) SetValues(announcements []container.UsedSpaceAnnouncement) {
x.announcements = announcements
}
// AnnounceSpaceRes groups resulting values of AnnounceContainerUsedSpace operation.
type AnnounceSpaceRes struct {
statusRes
}
// AnnounceContainerUsedSpace used by storage nodes to estimate their container
// sizes during lifetime. Use it only in storage node applications.
// AnnounceContainerUsedSpace sends request to announce volume of the space used for the container objects.
//
// 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.
func (c *Client) AnnounceContainerUsedSpace(
ctx context.Context,
announce []container.UsedSpaceAnnouncement,
opts ...CallOption,
) (*AnnounceSpaceRes, error) {
callOptions := c.defaultCallOptions() // apply all available options
for i := range opts {
opts[i](callOptions)
//
// Operation is asynchronous and no guaranteed even in the absence of errors.
// The required time is also not predictable.
//
// At this moment success can not be checked.
//
// Immediately panics if parameters are set incorrectly (see AnnounceSpacePrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in AnnounceSpaceRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) AnnounceContainerUsedSpace(ctx context.Context, prm AnnounceSpacePrm) (*AnnounceSpaceRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case len(prm.announcements) == 0:
panic("missing announcements")
}
// convert list of SDK announcement structures into NeoFS-API v2 list
v2announce := make([]*v2container.UsedSpaceAnnouncement, 0, len(announce))
for i := range announce {
v2announce = append(v2announce, announce[i].ToV2())
v2announce := make([]*v2container.UsedSpaceAnnouncement, 0, len(prm.announcements))
for i := range prm.announcements {
v2announce = append(v2announce, prm.announcements[i].ToV2())
}
// prepare body of the NeoFS-API v2 request and request itself
reqBody := new(v2container.AnnounceUsedSpaceRequestBody)
reqBody.SetAnnouncements(v2announce)
req := new(v2container.AnnounceUsedSpaceRequest)
// form request
var req v2container.AnnounceUsedSpaceRequest
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
// sign the request
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.AnnounceUsedSpace(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(AnnounceSpaceRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res AnnounceSpaceRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceUsedSpace(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return res, nil
return &res, nil
}

View file

@ -2,116 +2,120 @@ package client
import (
"context"
"fmt"
v2netmap "github.com/nspcc-dev/neofs-api-go/v2/netmap"
rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc"
"github.com/nspcc-dev/neofs-api-go/v2/rpc/client"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
// EndpointInfo represents versioned information about the node
// specified in the client.
type EndpointInfo struct {
// EndpointInfoPrm groups parameters of EndpointInfo operation.
//
// At the moment the operation is not parameterized, however,
// the structure is still declared for backward compatibility.
type EndpointInfoPrm struct{}
// EndpointInfoRes group resulting values of EndpointInfo operation.
type EndpointInfoRes struct {
statusRes
version *version.Version
ni *netmap.NodeInfo
}
// LatestVersion returns latest NeoFS API version in use.
func (e *EndpointInfo) LatestVersion() *version.Version {
return e.version
// LatestVersion returns latest NeoFS API protocol's version in use.
//
// Client doesn't retain value so modification is safe.
func (x EndpointInfoRes) LatestVersion() *version.Version {
return x.version
}
// NodeInfo returns information about the NeoFS node.
func (e *EndpointInfo) NodeInfo() *netmap.NodeInfo {
return e.ni
func (x *EndpointInfoRes) setLatestVersion(ver *version.Version) {
x.version = ver
}
type EndpointInfoRes struct {
statusRes
info *EndpointInfo
// NodeInfo returns information about the NeoFS node served on the remote endpoint.
//
// Client doesn't retain value so modification is safe.
func (x EndpointInfoRes) NodeInfo() *netmap.NodeInfo {
return x.ni
}
func (x EndpointInfoRes) Info() *EndpointInfo {
return x.info
func (x *EndpointInfoRes) setNodeInfo(info *netmap.NodeInfo) {
x.ni = info
}
func (x *EndpointInfoRes) setInfo(info *EndpointInfo) {
x.info = info
}
// EndpointInfo returns attributes, address and public key of the node, specified
// in client constructor via address or open connection. This can be used as a
// health check to see if node is alive and responses to requests.
// 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.
//
// 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.
func (c *Client) EndpointInfo(ctx context.Context, opts ...CallOption) (*EndpointInfoRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see EndpointInfoPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in EndpointInfoRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) EndpointInfo(ctx context.Context, _ EndpointInfoPrm) (*EndpointInfoRes, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
}
reqBody := new(v2netmap.LocalNodeInfoRequestBody)
// form request
var req v2netmap.LocalNodeInfoRequest
req := new(v2netmap.LocalNodeInfoRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.LocalNodeInfo(c.Raw(), req)
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(EndpointInfoRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res EndpointInfoRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
}
return res, nil
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.LocalNodeInfo(c.Raw(), &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2netmap.LocalNodeInfoResponse)
body := resp.GetBody()
res.setInfo(&EndpointInfo{
version: version.NewFromV2(body.GetVersion()),
ni: netmap.NewNodeInfoFromV2(body.GetNodeInfo()),
})
res.setLatestVersion(version.NewFromV2(body.GetVersion()))
res.setNodeInfo(netmap.NewNodeInfoFromV2(body.GetNodeInfo()))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}
// NetworkInfoPrm groups parameters of NetworkInfo operation.
//
// At the moment the operation is not parameterized, however,
// the structure is still declared for backward compatibility.
type NetworkInfoPrm struct{}
// NetworkInfoRes groups resulting values of NetworkInfo operation.
type NetworkInfoRes struct {
statusRes
info *netmap.NetworkInfo
}
// Info returns structured information about the NeoFS network.
//
// Client doesn't retain value so modification is safe.
func (x NetworkInfoRes) Info() *netmap.NetworkInfo {
return x.info
}
@ -120,57 +124,50 @@ func (x *NetworkInfoRes) setInfo(info *netmap.NetworkInfo) {
x.info = info
}
// NetworkInfo returns 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`.
// If WithNeoFSErrorParsing option has been provided, unsuccessful
// NeoFS status codes are returned as `error`, otherwise, are included
// in the returned result structure.
func (c *Client) NetworkInfo(ctx context.Context, opts ...CallOption) (*NetworkInfoRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see NetworkInfoPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in NetworkInfoRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) NetworkInfo(ctx context.Context, _ NetworkInfoPrm) (*NetworkInfoRes, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
}
reqBody := new(v2netmap.NetworkInfoRequestBody)
// form request
var req v2netmap.NetworkInfoRequest
req := new(v2netmap.NetworkInfoRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.NetworkInfo(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("v2 NetworkInfo RPC failure: %w", err)
}
// init call context
var (
res = new(NetworkInfoRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res NetworkInfoRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
}
return res, nil
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.NetworkInfo(c.Raw(), &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2netmap.NetworkInfoResponse)
res.setInfo(netmap.NewNetworkInfoFromV2(resp.GetBody().GetNetworkInfo()))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}

View file

@ -1461,17 +1461,11 @@ func (c *Client) attachV2SessionToken(opts *callOptions, hdr *v2session.RequestM
opCtx.SetAddress(info.addr)
opCtx.SetVerb(info.verb)
lt := new(v2session.TokenLifetime)
lt.SetIat(info.iat)
lt.SetNbf(info.nbf)
lt.SetExp(info.exp)
body := new(v2session.SessionTokenBody)
body.SetID(opts.session.ID())
body.SetOwnerID(opts.session.OwnerID().ToV2())
body.SetSessionKey(opts.session.SessionKey())
body.SetContext(opCtx)
body.SetLifetime(lt)
token := new(v2session.SessionToken)
token.SetBody(body)

View file

@ -1,94 +0,0 @@
package client
import (
"io"
"testing"
"github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-crypto/test"
"github.com/stretchr/testify/require"
)
type singleResponseStream struct {
called bool
resp object.GetResponse
}
func (x *singleResponseStream) Read(r *object.GetResponse) error {
if x.called {
return io.EOF
}
x.called = true
*r = x.resp
return nil
}
var key = test.DecodeKey(0)
func chunkResponse(c []byte) (r object.GetResponse) {
chunkPart := new(object.GetObjectPartChunk)
chunkPart.SetChunk(c)
body := new(object.GetResponseBody)
body.SetObjectPart(chunkPart)
r.SetBody(body)
if err := signature.SignServiceMessage(key, &r); err != nil {
panic(err)
}
return
}
func data(sz int) []byte {
data := make([]byte, sz)
for i := range data {
data[i] = byte(i) % ^byte(0)
}
return data
}
func checkFullRead(t *testing.T, r io.Reader, buf, payload []byte) {
var (
restored []byte
read int
)
for {
n, err := r.Read(buf)
read += n
restored = append(restored, buf[:n]...)
if err != nil {
require.Equal(t, err, io.EOF)
break
}
}
require.Equal(t, payload, restored)
require.EqualValues(t, len(payload), read)
}
func TestObjectPayloadReader_Read(t *testing.T) {
t.Run("read with tail", func(t *testing.T) {
payload := data(10)
buf := make([]byte, len(payload)-1)
var r io.Reader = &objectPayloadReader{
stream: &singleResponseStream{
resp: chunkResponse(payload),
},
}
checkFullRead(t, r, buf, payload)
})
}

View file

@ -51,8 +51,6 @@ type (
v2SessionReqInfo struct {
addr *refs.Address
verb v2session.ObjectSessionVerb
exp, nbf, iat uint64
}
)

View file

@ -6,7 +6,6 @@ import (
v2reputation "github.com/nspcc-dev/neofs-api-go/v2/reputation"
rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc"
"github.com/nspcc-dev/neofs-api-go/v2/rpc/client"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/reputation"
)
@ -14,26 +13,20 @@ import (
type AnnounceLocalTrustPrm struct {
epoch uint64
trusts []*reputation.Trust
trusts []reputation.Trust
}
// Epoch returns epoch in which the trust was assessed.
func (x AnnounceLocalTrustPrm) Epoch() uint64 {
return x.epoch
}
// SetEpoch sets epoch in which the trust was assessed.
// SetEpoch sets number of NeoFS epoch in which the trust was assessed.
// Required parameter, must not be zero.
func (x *AnnounceLocalTrustPrm) SetEpoch(epoch uint64) {
x.epoch = epoch
}
// Trusts returns list of local trust values.
func (x AnnounceLocalTrustPrm) Trusts() []*reputation.Trust {
return x.trusts
}
// SetTrusts sets list of local trust values.
func (x *AnnounceLocalTrustPrm) SetTrusts(trusts []*reputation.Trust) {
// SetValues sets values describing trust of the client to the NeoFS network participants.
// Required parameter. Must not be empty.
//
// Must not be mutated before the end of the operation.
func (x *AnnounceLocalTrustPrm) SetValues(trusts []reputation.Trust) {
x.trusts = trusts
}
@ -42,59 +35,66 @@ type AnnounceLocalTrustRes struct {
statusRes
}
// AnnounceLocalTrust announces node's local trusts through NeoFS API call.
// AnnounceLocalTrust sends client's trust values to the NeoFS network participants.
//
// 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.
func (c *Client) AnnounceLocalTrust(ctx context.Context, prm AnnounceLocalTrustPrm, opts ...CallOption) (*AnnounceLocalTrustRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see AnnounceLocalTrustPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in AnnounceLocalTrustRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) AnnounceLocalTrust(ctx context.Context, prm AnnounceLocalTrustPrm) (*AnnounceLocalTrustRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.epoch == 0:
panic("zero epoch")
case len(prm.trusts) == 0:
panic("missing trusts")
}
// form request body
reqBody := new(v2reputation.AnnounceLocalTrustRequestBody)
reqBody.SetEpoch(prm.Epoch())
reqBody.SetTrusts(reputation.TrustsToV2(prm.Trusts()))
reqBody.SetEpoch(prm.epoch)
trusts := make([]*reputation.Trust, 0, len(prm.trusts))
for i := range prm.trusts {
trusts = append(trusts, &prm.trusts[i])
}
reqBody.SetTrusts(reputation.TrustsToV2(trusts))
// form request
var req v2reputation.AnnounceLocalTrustRequest
req := new(v2reputation.AnnounceLocalTrustRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.AnnounceLocalTrust(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, err
}
// init call context
var (
res = new(AnnounceLocalTrustRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res AnnounceLocalTrustRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceLocalTrust(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return res, nil
return &res, nil
}
// AnnounceIntermediateTrustPrm groups parameters of AnnounceIntermediateTrust operation.
@ -103,35 +103,27 @@ type AnnounceIntermediateTrustPrm struct {
iter uint32
trust *reputation.PeerToPeerTrust
}
func (x *AnnounceIntermediateTrustPrm) Epoch() uint64 {
return x.epoch
trustSet bool
trust reputation.PeerToPeerTrust
}
// SetEpoch sets number of NeoFS epoch with which client's calculation algorithm is initialized.
// Required parameter, must not be zero.
func (x *AnnounceIntermediateTrustPrm) SetEpoch(epoch uint64) {
x.epoch = epoch
}
// Iteration returns sequence number of the iteration.
func (x AnnounceIntermediateTrustPrm) Iteration() uint32 {
return x.iter
}
// SetIteration sets sequence number of the iteration.
// SetIteration sets current sequence number of the client's calculation algorithm.
// By default, corresponds to initial (zero) iteration.
func (x *AnnounceIntermediateTrustPrm) SetIteration(iter uint32) {
x.iter = iter
}
// Trust returns current global trust value computed at the specified iteration.
func (x AnnounceIntermediateTrustPrm) Trust() *reputation.PeerToPeerTrust {
return x.trust
}
// SetTrust sets current global trust value computed at the specified iteration.
func (x *AnnounceIntermediateTrustPrm) SetTrust(trust *reputation.PeerToPeerTrust) {
// SetCurrentValue sets current global trust value computed at the specified iteration
//of the client's calculation algorithm. Required parameter.
func (x *AnnounceIntermediateTrustPrm) SetCurrentValue(trust reputation.PeerToPeerTrust) {
x.trust = trust
x.trustSet = true
}
// AnnounceIntermediateTrustRes groups results of AnnounceIntermediateTrust operation.
@ -139,58 +131,59 @@ type AnnounceIntermediateTrustRes struct {
statusRes
}
// AnnounceIntermediateTrust announces node's intermediate trusts through NeoFS API call.
// AnnounceIntermediateTrust sends global trust values calculated for the specified NeoFS network participants
// at some stage of client's calculation algorithm.
//
// 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.
func (c *Client) AnnounceIntermediateTrust(ctx context.Context, prm AnnounceIntermediateTrustPrm, opts ...CallOption) (*AnnounceIntermediateTrustRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
//
// Immediately panics if parameters are set incorrectly (see AnnounceIntermediateTrustPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in AnnounceIntermediateTrustRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) AnnounceIntermediateTrust(ctx context.Context, prm AnnounceIntermediateTrustPrm) (*AnnounceIntermediateTrustRes, error) {
// check parameters
switch {
case ctx == nil:
panic(panicMsgMissingContext)
case prm.epoch == 0:
panic("zero epoch")
case !prm.trustSet:
panic("current trust value not set")
}
// form request body
reqBody := new(v2reputation.AnnounceIntermediateResultRequestBody)
reqBody.SetEpoch(prm.Epoch())
reqBody.SetIteration(prm.Iteration())
reqBody.SetTrust(prm.Trust().ToV2())
reqBody.SetEpoch(prm.epoch)
reqBody.SetIteration(prm.iter)
reqBody.SetTrust(prm.trust.ToV2())
// form request
var req v2reputation.AnnounceIntermediateResultRequest
req := new(v2reputation.AnnounceIntermediateResultRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.AnnounceIntermediateResult(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, err
}
// init call context
var (
res = new(AnnounceIntermediateTrustRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res AnnounceIntermediateTrustRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.AnnounceIntermediateResult(c.Raw(), &req, client.WithContext(ctx))
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return res, nil
return &res, nil
}

View file

@ -2,18 +2,24 @@ package client
import (
"context"
"errors"
"fmt"
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"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/owner"
)
var errMalformedResponseBody = errors.New("malformed response body")
// CreateSessionPrm groups parameters of CreateSession operation.
type CreateSessionPrm struct {
exp uint64
}
// SetExp sets number of the last NepFS epoch in the lifetime of the session after which it will be expired.
func (x *CreateSessionPrm) SetExp(exp uint64) {
x.exp = exp
}
// CreateSessionRes groups resulting values of CreateSession operation.
type CreateSessionRes struct {
statusRes
@ -26,6 +32,9 @@ func (x *CreateSessionRes) setID(id []byte) {
x.id = id
}
// ID returns identifier of the opened session in a binary NeoFS API protocol format.
//
// Client doesn't retain value so modification is safe.
func (x CreateSessionRes) ID() []byte {
return x.id
}
@ -34,66 +43,69 @@ func (x *CreateSessionRes) setSessionKey(key []byte) {
x.sessionKey = key
}
func (x CreateSessionRes) SessionKey() []byte {
// PublicKey returns public key of the opened session in a binary NeoFS API protocol format.
func (x CreateSessionRes) PublicKey() []byte {
return x.sessionKey
}
// CreateSession creates session through NeoFS API call.
// CreateSession opens a session with the node server on the remote endpoint.
// The session lifetime coincides with the server lifetime. Results can be written
// to session token which can be later attached to the requests.
//
// Any client's internal or transport errors are returned as error,
// NeoFS status codes are included in the returned results.
func (c *Client) CreateSession(ctx context.Context, expiration uint64, opts ...CallOption) (*CreateSessionRes, error) {
// apply all available options
callOptions := c.defaultCallOptions()
for i := range opts {
opts[i](callOptions)
// 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 CreateSessionPrm docs).
// Context is required and must not be nil. It is used for network communication.
//
// Exactly one return value is non-nil. Server status return is returned in CreateSessionRes.
// Reflects all internal errors in second return value (transport problems, response processing, etc.).
func (c *Client) CreateSession(ctx context.Context, prm CreateSessionPrm) (*CreateSessionRes, error) {
// check context
if ctx == nil {
panic(panicMsgMissingContext)
}
ownerID := owner.NewIDFromPublicKey(&callOptions.key.PublicKey)
ownerID := owner.NewIDFromPublicKey(&c.opts.key.PublicKey)
// form request body
reqBody := new(v2session.CreateRequestBody)
reqBody.SetOwnerID(ownerID.ToV2())
reqBody.SetExpiration(expiration)
reqBody.SetExpiration(prm.exp)
// for request
var req v2session.CreateRequest
req := new(v2session.CreateRequest)
req.SetBody(reqBody)
req.SetMetaHeader(v2MetaHeaderFromOpts(callOptions))
err := v2signature.SignServiceMessage(callOptions.key, req)
if err != nil {
return nil, err
}
resp, err := rpcapi.CreateSession(c.Raw(), req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("transport error: %w", err)
}
// init call context
var (
res = new(CreateSessionRes)
procPrm processResponseV2Prm
procRes processResponseV2Res
cc contextCall
res CreateSessionRes
)
procPrm.callOpts = callOptions
procPrm.resp = resp
procRes.statusRes = res
// process response in general
if c.processResponseV2(&procRes, procPrm) {
if procRes.cliErr != nil {
return nil, procRes.cliErr
}
return res, nil
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.CreateSession(c.Raw(), &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2session.CreateResponse)
body := resp.GetBody()
res.setID(body.GetID())
res.setSessionKey(body.GetSessionKey())
}
return res, nil
// process call
if !cc.processCall() {
return nil, cc.err
}
return &res, nil
}

View file

@ -12,10 +12,6 @@ import (
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"
container "github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
eacl "github.com/nspcc-dev/neofs-sdk-go/eacl"
owner "github.com/nspcc-dev/neofs-sdk-go/owner"
)
// MockClient is a mock of Client interface.
@ -42,12 +38,9 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder {
}
// AnnounceContainerUsedSpace mocks base method.
func (m *MockClient) AnnounceContainerUsedSpace(arg0 context.Context, arg1 []container.UsedSpaceAnnouncement, arg2 ...client0.CallOption) (*client0.AnnounceSpaceRes, error) {
func (m *MockClient) AnnounceContainerUsedSpace(arg0 context.Context, arg1 client0.AnnounceSpacePrm) (*client0.AnnounceSpaceRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AnnounceContainerUsedSpace", varargs...)
ret0, _ := ret[0].(*client0.AnnounceSpaceRes)
ret1, _ := ret[1].(error)
@ -55,19 +48,16 @@ func (m *MockClient) AnnounceContainerUsedSpace(arg0 context.Context, arg1 []con
}
// AnnounceContainerUsedSpace indicates an expected call of AnnounceContainerUsedSpace.
func (mr *MockClientMockRecorder) AnnounceContainerUsedSpace(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) AnnounceContainerUsedSpace(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
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, arg2 ...client0.CallOption) (*client0.AnnounceIntermediateTrustRes, error) {
func (m *MockClient) AnnounceIntermediateTrust(arg0 context.Context, arg1 client0.AnnounceIntermediateTrustPrm) (*client0.AnnounceIntermediateTrustRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AnnounceIntermediateTrust", varargs...)
ret0, _ := ret[0].(*client0.AnnounceIntermediateTrustRes)
ret1, _ := ret[1].(error)
@ -75,19 +65,16 @@ func (m *MockClient) AnnounceIntermediateTrust(arg0 context.Context, arg1 client
}
// AnnounceIntermediateTrust indicates an expected call of AnnounceIntermediateTrust.
func (mr *MockClientMockRecorder) AnnounceIntermediateTrust(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) AnnounceIntermediateTrust(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
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, arg2 ...client0.CallOption) (*client0.AnnounceLocalTrustRes, error) {
func (m *MockClient) AnnounceLocalTrust(arg0 context.Context, arg1 client0.AnnounceLocalTrustPrm) (*client0.AnnounceLocalTrustRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AnnounceLocalTrust", varargs...)
ret0, _ := ret[0].(*client0.AnnounceLocalTrustRes)
ret1, _ := ret[1].(error)
@ -95,9 +82,9 @@ func (m *MockClient) AnnounceLocalTrust(arg0 context.Context, arg1 client0.Annou
}
// AnnounceLocalTrust indicates an expected call of AnnounceLocalTrust.
func (mr *MockClientMockRecorder) AnnounceLocalTrust(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) AnnounceLocalTrust(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AnnounceLocalTrust", reflect.TypeOf((*MockClient)(nil).AnnounceLocalTrust), varargs...)
}
@ -116,12 +103,9 @@ func (mr *MockClientMockRecorder) Conn() *gomock.Call {
}
// CreateSession mocks base method.
func (m *MockClient) CreateSession(arg0 context.Context, arg1 uint64, arg2 ...client0.CallOption) (*client0.CreateSessionRes, error) {
func (m *MockClient) CreateSession(arg0 context.Context, arg1 client0.CreateSessionPrm) (*client0.CreateSessionRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "CreateSession", varargs...)
ret0, _ := ret[0].(*client0.CreateSessionRes)
ret1, _ := ret[1].(error)
@ -129,19 +113,16 @@ func (m *MockClient) CreateSession(arg0 context.Context, arg1 uint64, arg2 ...cl
}
// CreateSession indicates an expected call of CreateSession.
func (mr *MockClientMockRecorder) CreateSession(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) CreateSession(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSession", reflect.TypeOf((*MockClient)(nil).CreateSession), varargs...)
}
// DeleteContainer mocks base method.
func (m *MockClient) DeleteContainer(arg0 context.Context, arg1 *cid.ID, arg2 ...client0.CallOption) (*client0.ContainerDeleteRes, error) {
func (m *MockClient) DeleteContainer(arg0 context.Context, arg1 client0.ContainerDeletePrm) (*client0.ContainerDeleteRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "DeleteContainer", varargs...)
ret0, _ := ret[0].(*client0.ContainerDeleteRes)
ret1, _ := ret[1].(error)
@ -149,9 +130,9 @@ func (m *MockClient) DeleteContainer(arg0 context.Context, arg1 *cid.ID, arg2 ..
}
// DeleteContainer indicates an expected call of DeleteContainer.
func (mr *MockClientMockRecorder) DeleteContainer(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) DeleteContainer(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteContainer", reflect.TypeOf((*MockClient)(nil).DeleteContainer), varargs...)
}
@ -176,12 +157,9 @@ func (mr *MockClientMockRecorder) DeleteObject(arg0, arg1 interface{}, arg2 ...i
}
// EACL mocks base method.
func (m *MockClient) EACL(arg0 context.Context, arg1 *cid.ID, arg2 ...client0.CallOption) (*client0.EACLRes, error) {
func (m *MockClient) EACL(arg0 context.Context, arg1 client0.EACLPrm) (*client0.EACLRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "EACL", varargs...)
ret0, _ := ret[0].(*client0.EACLRes)
ret1, _ := ret[1].(error)
@ -189,19 +167,16 @@ func (m *MockClient) EACL(arg0 context.Context, arg1 *cid.ID, arg2 ...client0.Ca
}
// EACL indicates an expected call of EACL.
func (mr *MockClientMockRecorder) EACL(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) EACL(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EACL", reflect.TypeOf((*MockClient)(nil).EACL), varargs...)
}
// EndpointInfo mocks base method.
func (m *MockClient) EndpointInfo(arg0 context.Context, arg1 ...client0.CallOption) (*client0.EndpointInfoRes, error) {
func (m *MockClient) EndpointInfo(arg0 context.Context, arg1 client0.EndpointInfoPrm) (*client0.EndpointInfoRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
varargs := []interface{}{arg0, arg1}
ret := m.ctrl.Call(m, "EndpointInfo", varargs...)
ret0, _ := ret[0].(*client0.EndpointInfoRes)
ret1, _ := ret[1].(error)
@ -209,39 +184,33 @@ func (m *MockClient) EndpointInfo(arg0 context.Context, arg1 ...client0.CallOpti
}
// EndpointInfo indicates an expected call of EndpointInfo.
func (mr *MockClientMockRecorder) EndpointInfo(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) EndpointInfo(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EndpointInfo", reflect.TypeOf((*MockClient)(nil).EndpointInfo), varargs...)
}
// GetBalance mocks base method.
func (m *MockClient) GetBalance(arg0 context.Context, arg1 *owner.ID, arg2 ...client0.CallOption) (*client0.BalanceOfRes, error) {
func (m *MockClient) GetBalance(arg0 context.Context, arg1 client0.GetBalancePrm) (*client0.GetBalanceRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetBalance", varargs...)
ret0, _ := ret[0].(*client0.BalanceOfRes)
ret0, _ := ret[0].(*client0.GetBalanceRes)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBalance indicates an expected call of GetBalance.
func (mr *MockClientMockRecorder) GetBalance(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) GetBalance(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBalance", reflect.TypeOf((*MockClient)(nil).GetBalance), varargs...)
}
// GetContainer mocks base method.
func (m *MockClient) GetContainer(arg0 context.Context, arg1 *cid.ID, arg2 ...client0.CallOption) (*client0.ContainerGetRes, error) {
func (m *MockClient) GetContainer(arg0 context.Context, arg1 client0.ContainerGetPrm) (*client0.ContainerGetRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "GetContainer", varargs...)
ret0, _ := ret[0].(*client0.ContainerGetRes)
ret1, _ := ret[1].(error)
@ -249,9 +218,9 @@ func (m *MockClient) GetContainer(arg0 context.Context, arg1 *cid.ID, arg2 ...cl
}
// GetContainer indicates an expected call of GetContainer.
func (mr *MockClientMockRecorder) GetContainer(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) GetContainer(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetContainer", reflect.TypeOf((*MockClient)(nil).GetContainer), varargs...)
}
@ -316,12 +285,9 @@ func (mr *MockClientMockRecorder) HeadObject(arg0, arg1 interface{}, arg2 ...int
}
// ListContainers mocks base method.
func (m *MockClient) ListContainers(arg0 context.Context, arg1 *owner.ID, arg2 ...client0.CallOption) (*client0.ContainerListRes, error) {
func (m *MockClient) ListContainers(arg0 context.Context, arg1 client0.ContainerListPrm) (*client0.ContainerListRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "ListContainers", varargs...)
ret0, _ := ret[0].(*client0.ContainerListRes)
ret1, _ := ret[1].(error)
@ -329,19 +295,16 @@ func (m *MockClient) ListContainers(arg0 context.Context, arg1 *owner.ID, arg2 .
}
// ListContainers indicates an expected call of ListContainers.
func (mr *MockClientMockRecorder) ListContainers(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) ListContainers(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListContainers", reflect.TypeOf((*MockClient)(nil).ListContainers), varargs...)
}
// NetworkInfo mocks base method.
func (m *MockClient) NetworkInfo(arg0 context.Context, arg1 ...client0.CallOption) (*client0.NetworkInfoRes, error) {
func (m *MockClient) NetworkInfo(arg0 context.Context, arg1 client0.NetworkInfoPrm) (*client0.NetworkInfoRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
varargs := []interface{}{arg0, arg1}
ret := m.ctrl.Call(m, "NetworkInfo", varargs...)
ret0, _ := ret[0].(*client0.NetworkInfoRes)
ret1, _ := ret[1].(error)
@ -349,9 +312,9 @@ func (m *MockClient) NetworkInfo(arg0 context.Context, arg1 ...client0.CallOptio
}
// NetworkInfo indicates an expected call of NetworkInfo.
func (mr *MockClientMockRecorder) NetworkInfo(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) NetworkInfo(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetworkInfo", reflect.TypeOf((*MockClient)(nil).NetworkInfo), varargs...)
}
@ -376,12 +339,9 @@ func (mr *MockClientMockRecorder) ObjectPayloadRangeData(arg0, arg1 interface{},
}
// PutContainer mocks base method.
func (m *MockClient) PutContainer(arg0 context.Context, arg1 *container.Container, arg2 ...client0.CallOption) (*client0.ContainerPutRes, error) {
func (m *MockClient) PutContainer(arg0 context.Context, arg1 client0.ContainerPutPrm) (*client0.ContainerPutRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "PutContainer", varargs...)
ret0, _ := ret[0].(*client0.ContainerPutRes)
ret1, _ := ret[1].(error)
@ -389,9 +349,9 @@ func (m *MockClient) PutContainer(arg0 context.Context, arg1 *container.Containe
}
// PutContainer indicates an expected call of PutContainer.
func (mr *MockClientMockRecorder) PutContainer(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) PutContainer(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutContainer", reflect.TypeOf((*MockClient)(nil).PutContainer), varargs...)
}
@ -450,12 +410,9 @@ func (mr *MockClientMockRecorder) SearchObjects(arg0, arg1 interface{}, arg2 ...
}
// SetEACL mocks base method.
func (m *MockClient) SetEACL(arg0 context.Context, arg1 *eacl.Table, arg2 ...client0.CallOption) (*client0.SetEACLRes, error) {
func (m *MockClient) SetEACL(arg0 context.Context, arg1 client0.SetEACLPrm) (*client0.SetEACLRes, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "SetEACL", varargs...)
ret0, _ := ret[0].(*client0.SetEACLRes)
ret1, _ := ret[1].(error)
@ -463,8 +420,8 @@ func (m *MockClient) SetEACL(arg0 context.Context, arg1 *eacl.Table, arg2 ...cli
}
// SetEACL indicates an expected call of SetEACL.
func (mr *MockClientMockRecorder) SetEACL(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
func (mr *MockClientMockRecorder) SetEACL(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
varargs := []interface{}{arg0, arg1}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEACL", reflect.TypeOf((*MockClient)(nil).SetEACL), varargs...)
}

View file

@ -30,16 +30,16 @@ import (
// Client is a wrapper for client.Client to generate mock.
type Client interface {
GetBalance(context.Context, *owner.ID, ...client.CallOption) (*client.BalanceOfRes, error)
PutContainer(context.Context, *container.Container, ...client.CallOption) (*client.ContainerPutRes, error)
GetContainer(context.Context, *cid.ID, ...client.CallOption) (*client.ContainerGetRes, error)
ListContainers(context.Context, *owner.ID, ...client.CallOption) (*client.ContainerListRes, error)
DeleteContainer(context.Context, *cid.ID, ...client.CallOption) (*client.ContainerDeleteRes, error)
EACL(context.Context, *cid.ID, ...client.CallOption) (*client.EACLRes, error)
SetEACL(context.Context, *eacl.Table, ...client.CallOption) (*client.SetEACLRes, error)
AnnounceContainerUsedSpace(context.Context, []container.UsedSpaceAnnouncement, ...client.CallOption) (*client.AnnounceSpaceRes, error)
EndpointInfo(context.Context, ...client.CallOption) (*client.EndpointInfoRes, error)
NetworkInfo(context.Context, ...client.CallOption) (*client.NetworkInfoRes, error)
GetBalance(context.Context, client.GetBalancePrm) (*client.GetBalanceRes, error)
PutContainer(context.Context, client.ContainerPutPrm) (*client.ContainerPutRes, error)
GetContainer(context.Context, client.ContainerGetPrm) (*client.ContainerGetRes, error)
ListContainers(context.Context, client.ContainerListPrm) (*client.ContainerListRes, error)
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)
PutObject(context.Context, *client.PutObjectParams, ...client.CallOption) (*client.ObjectPutRes, error)
DeleteObject(context.Context, *client.DeleteObjectParams, ...client.CallOption) (*client.ObjectDeleteRes, error)
GetObject(context.Context, *client.GetObjectParams, ...client.CallOption) (*client.ObjectGetRes, error)
@ -47,9 +47,9 @@ type Client interface {
ObjectPayloadRangeData(context.Context, *client.RangeDataParams, ...client.CallOption) (*client.ObjectRangeRes, error)
HashObjectPayloadRanges(context.Context, *client.RangeChecksumParams, ...client.CallOption) (*client.ObjectRangeHashRes, error)
SearchObjects(context.Context, *client.SearchObjectParams, ...client.CallOption) (*client.ObjectSearchRes, error)
AnnounceLocalTrust(context.Context, client.AnnounceLocalTrustPrm, ...client.CallOption) (*client.AnnounceLocalTrustRes, error)
AnnounceIntermediateTrust(context.Context, client.AnnounceIntermediateTrustPrm, ...client.CallOption) (*client.AnnounceIntermediateTrustRes, error)
CreateSession(context.Context, uint64, ...client.CallOption) (*client.CreateSessionRes, 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
@ -174,7 +174,6 @@ type Container interface {
DeleteContainer(ctx context.Context, cid *cid.ID, opts ...CallOption) error
GetEACL(ctx context.Context, cid *cid.ID, opts ...CallOption) (*eacl.Table, error)
SetEACL(ctx context.Context, table *eacl.Table, opts ...CallOption) error
AnnounceContainerUsedSpace(ctx context.Context, announce []container.UsedSpaceAnnouncement, opts ...CallOption) error
}
type Accounting interface {
@ -263,6 +262,11 @@ func newPool(ctx context.Context, options *BuilderOptions) (Pool, error) {
inner := make([]*innerPool, len(options.nodesParams))
var atLeastOneHealthy bool
var cliPrm client.CreateSessionPrm
cliPrm.SetExp(options.SessionExpirationEpoch)
for i, params := range options.nodesParams {
clientPacks := make([]*clientPack, len(params.weights))
for j, address := range params.addresses {
@ -274,7 +278,7 @@ func newPool(ctx context.Context, options *BuilderOptions) (Pool, error) {
return nil, err
}
var healthy bool
cliRes, err := c.CreateSession(ctx, options.SessionExpirationEpoch)
cliRes, err := c.CreateSession(ctx, cliPrm)
if err != nil && options.Logger != nil {
options.Logger.Warn("failed to create neofs session token for client",
zap.String("address", address),
@ -353,14 +357,23 @@ func updateInnerNodesHealth(ctx context.Context, pool *pool, i int, options *Bui
healthyChanged := false
wg := sync.WaitGroup{}
var (
prmEndpoint client.EndpointInfoPrm
prmSession client.CreateSessionPrm
)
prmSession.SetExp(options.SessionExpirationEpoch)
for j, cPack := range p.clientPacks {
wg.Add(1)
go func(j int, client Client) {
go func(j int, cli Client) {
defer wg.Done()
ok := true
tctx, c := context.WithTimeout(ctx, options.NodeRequestTimeout)
defer c()
if _, err := client.EndpointInfo(tctx); err != nil {
if _, err := cli.EndpointInfo(tctx, prmEndpoint); err != nil {
ok = false
bufferWeights[j] = 0
}
@ -371,7 +384,7 @@ func updateInnerNodesHealth(ctx context.Context, pool *pool, i int, options *Bui
if ok {
bufferWeights[j] = options.nodesParams[i].weights[j]
if !cp.healthy {
if cliRes, err := client.CreateSession(ctx, options.SessionExpirationEpoch); err != nil {
if cliRes, err := cli.CreateSession(ctx, prmSession); err != nil {
ok = false
bufferWeights[j] = 0
} else {
@ -488,7 +501,11 @@ func (p *pool) conn(ctx context.Context, cfg *callConfig) (*clientPack, []client
cacheKey := formCacheKey(cp.address, key)
sessionToken = p.cache.Get(cacheKey)
if sessionToken == nil {
cliRes, err := cp.client.CreateSession(ctx, math.MaxUint32, clientCallOptions...)
var cliPrm client.CreateSessionPrm
cliPrm.SetExp(math.MaxUint32)
cliRes, err := cp.client.CreateSession(ctx, cliPrm)
if err != nil {
return nil, nil, err
}
@ -496,6 +513,8 @@ func (p *pool) conn(ctx context.Context, cfg *callConfig) (*clientPack, []client
ownerID := owner.NewIDFromPublicKey(&key.PublicKey)
sessionToken = sessionTokenForOwner(ownerID, cliRes)
cfg.stoken = sessionToken
_ = p.cache.Put(cacheKey, sessionToken)
}
}
@ -733,12 +752,22 @@ func (p *pool) SearchObject(ctx context.Context, params *client.SearchObjectPara
func (p *pool) PutContainer(ctx context.Context, cnr *container.Container, opts ...CallOption) (*cid.ID, error) {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return nil, err
}
res, err := cp.client.PutContainer(ctx, cnr, options...)
var cliPrm client.ContainerPutPrm
if cnr != nil {
cliPrm.SetContainer(*cnr)
}
if cfg.stoken != nil {
cliPrm.SetSessionToken(*cfg.stoken)
}
res, err := cp.client.PutContainer(ctx, cliPrm)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
@ -754,12 +783,18 @@ func (p *pool) PutContainer(ctx context.Context, cnr *container.Container, opts
func (p *pool) GetContainer(ctx context.Context, cid *cid.ID, opts ...CallOption) (*container.Container, error) {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return nil, err
}
res, err := cp.client.GetContainer(ctx, cid, options...)
var cliPrm client.ContainerGetPrm
if cid != nil {
cliPrm.SetContainer(*cid)
}
res, err := cp.client.GetContainer(ctx, cliPrm)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
@ -775,12 +810,18 @@ func (p *pool) GetContainer(ctx context.Context, cid *cid.ID, opts ...CallOption
func (p *pool) ListContainers(ctx context.Context, ownerID *owner.ID, opts ...CallOption) ([]*cid.ID, error) {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return nil, err
}
res, err := cp.client.ListContainers(ctx, ownerID, options...)
var cliPrm client.ContainerListPrm
if ownerID != nil {
cliPrm.SetAccount(*ownerID)
}
res, err := cp.client.ListContainers(ctx, cliPrm)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
@ -791,17 +832,27 @@ func (p *pool) ListContainers(ctx context.Context, ownerID *owner.ID, opts ...Ca
return nil, err
}
return res.IDList(), nil
return res.Containers(), nil
}
func (p *pool) DeleteContainer(ctx context.Context, cid *cid.ID, opts ...CallOption) error {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return err
}
_, err = cp.client.DeleteContainer(ctx, cid, options...)
var cliPrm client.ContainerDeletePrm
if cid != nil {
cliPrm.SetContainer(*cid)
}
if cfg.stoken != nil {
cliPrm.SetSessionToken(*cfg.stoken)
}
_, err = cp.client.DeleteContainer(ctx, cliPrm)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
@ -815,12 +866,18 @@ func (p *pool) DeleteContainer(ctx context.Context, cid *cid.ID, opts ...CallOpt
func (p *pool) GetEACL(ctx context.Context, cid *cid.ID, opts ...CallOption) (*eacl.Table, error) {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return nil, err
}
res, err := cp.client.EACL(ctx, cid, options...)
var cliPrm client.EACLPrm
if cid != nil {
cliPrm.SetContainer(*cid)
}
res, err := cp.client.EACL(ctx, cliPrm)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
@ -836,12 +893,22 @@ func (p *pool) GetEACL(ctx context.Context, cid *cid.ID, opts ...CallOption) (*e
func (p *pool) SetEACL(ctx context.Context, table *eacl.Table, opts ...CallOption) error {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return err
}
_, err = cp.client.SetEACL(ctx, table, options...)
var cliPrm client.SetEACLPrm
if table != nil {
cliPrm.SetTable(*table)
}
if cfg.stoken != nil {
cliPrm.SetSessionToken(*cfg.stoken)
}
_, err = cp.client.SetEACL(ctx, cliPrm)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
@ -853,33 +920,20 @@ func (p *pool) SetEACL(ctx context.Context, table *eacl.Table, opts ...CallOptio
return err
}
func (p *pool) AnnounceContainerUsedSpace(ctx context.Context, announce []container.UsedSpaceAnnouncement, opts ...CallOption) error {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
if err != nil {
return err
}
_, err = cp.client.AnnounceContainerUsedSpace(ctx, announce, options...)
if p.checkSessionTokenErr(err, cp.address) && !cfg.isRetry {
opts = append(opts, retry())
return p.AnnounceContainerUsedSpace(ctx, announce, opts...)
}
// here err already carries both status and client errors
return err
}
func (p *pool) Balance(ctx context.Context, o *owner.ID, opts ...CallOption) (*accounting.Decimal, error) {
cfg := cfgFromOpts(opts...)
cp, options, err := p.conn(ctx, cfg)
cp, _, err := p.conn(ctx, cfg)
if err != nil {
return nil, err
}
res, err := cp.client.GetBalance(ctx, o, options...)
var cliPrm client.GetBalancePrm
if o != nil {
cliPrm.SetAccount(*o)
}
res, err := cp.client.GetBalance(ctx, cliPrm)
if err != nil { // here err already carries both status and client errors
return nil, err
}
@ -898,6 +952,13 @@ func (p *pool) WaitForContainerPresence(ctx context.Context, cid *cid.ID, pollPa
defer ticker.Stop()
wdone := wctx.Done()
done := ctx.Done()
var cliPrm client.ContainerGetPrm
if cid != nil {
cliPrm.SetContainer(*cid)
}
for {
select {
case <-done:
@ -905,7 +966,7 @@ func (p *pool) WaitForContainerPresence(ctx context.Context, cid *cid.ID, pollPa
case <-wdone:
return wctx.Err()
case <-ticker.C:
_, err = conn.GetContainer(ctx, cid)
_, err = conn.GetContainer(ctx, cliPrm)
if err == nil {
return nil
}
@ -930,7 +991,7 @@ func sessionTokenForOwner(id *owner.ID, cliRes *client.CreateSessionRes) *sessio
st := session.NewToken()
st.SetOwnerID(id)
st.SetID(cliRes.ID())
st.SetSessionKey(cliRes.SessionKey())
st.SetSessionKey(cliRes.PublicKey())
return st
}

View file

@ -152,7 +152,7 @@ func TestOneNode(t *testing.T) {
clientBuilder := func(opts ...client.Option) (Client, error) {
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(tok, nil)
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(&client.EndpointInfo{}, nil).AnyTimes()
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(&client.EndpointInfoRes{}, nil).AnyTimes()
return mockClient, nil
}
@ -189,7 +189,7 @@ func TestTwoNodes(t *testing.T) {
tokens = append(tokens, tok)
return tok, err
})
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(&client.EndpointInfo{}, nil).AnyTimes()
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(&client.EndpointInfoRes{}, nil).AnyTimes()
return mockClient, nil
}
@ -222,7 +222,7 @@ func TestOneOfTwoFailed(t *testing.T) {
clientBuilder := func(opts ...client.Option) (Client, error) {
clientCount++
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
tok := newToken(t)
tokens = append(tokens, tok)
return tok, nil
@ -235,7 +235,7 @@ func TestOneOfTwoFailed(t *testing.T) {
tokens = append(tokens, tok)
return tok, nil
}).AnyTimes()
mockClient2.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).DoAndReturn(func(_ interface{}, _ ...interface{}) (*client.EndpointInfo, error) {
mockClient2.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).DoAndReturn(func(_ interface{}, _ ...interface{}) (*client.EndpointInfoRes, error) {
return nil, fmt.Errorf("error")
}).AnyTimes()
@ -275,7 +275,7 @@ func TestTwoFailed(t *testing.T) {
clientBuilder := func(opts ...client.Option) (Client, error) {
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("error")).AnyTimes()
return mockClient, nil
}
@ -309,7 +309,7 @@ func TestSessionCache(t *testing.T) {
var tokens []*session.Token
clientBuilder := func(opts ...client.Option) (Client, error) {
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
tok := session.NewToken()
uid, err := uuid.New().MarshalBinary()
require.NoError(t, err)
@ -373,7 +373,7 @@ func TestPriority(t *testing.T) {
clientBuilder := func(opts ...client.Option) (Client, error) {
clientCount++
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
tok := newToken(t)
tokens = append(tokens, tok)
return tok, nil
@ -435,7 +435,7 @@ func TestSessionCacheWithKey(t *testing.T) {
var tokens []*session.Token
clientBuilder := func(opts ...client.Option) (Client, error) {
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).DoAndReturn(func(_, _ interface{}, _ ...interface{}) (*session.Token, error) {
tok := session.NewToken()
uid, err := uuid.New().MarshalBinary()
require.NoError(t, err)
@ -487,7 +487,7 @@ func TestSessionTokenOwner(t *testing.T) {
ctrl := gomock.NewController(t)
clientBuilder := func(opts ...client.Option) (Client, error) {
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(&client.CreateSessionRes{}, nil).AnyTimes()
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(&client.CreateSessionRes{}, nil).AnyTimes()
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(&client.EndpointInfoRes{}, nil).AnyTimes()
return mockClient, nil
}
@ -525,9 +525,9 @@ func TestWaitPresence(t *testing.T) {
ctrl := gomock.NewController(t)
mockClient := NewMockClient(ctrl)
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
mockClient.EXPECT().CreateSession(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
mockClient.EXPECT().EndpointInfo(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
mockClient.EXPECT().GetContainer(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
mockClient.EXPECT().GetContainer(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
cache, err := NewCache()
require.NoError(t, err)

View file

@ -48,11 +48,11 @@ type clientMock struct {
err error
}
func (c *clientMock) EndpointInfo(context.Context, ...client.CallOption) (*client.EndpointInfoRes, error) {
func (c *clientMock) EndpointInfo(context.Context, client.EndpointInfoPrm) (*client.EndpointInfoRes, error) {
return nil, nil
}
func (c *clientMock) NetworkInfo(context.Context, ...client.CallOption) (*client.NetworkInfoRes, error) {
func (c *clientMock) NetworkInfo(context.Context, client.NetworkInfoPrm) (*client.NetworkInfoRes, error) {
return nil, nil
}