[#337] client: Add option to specify callback of response information

There is a need to analyze some response information in API client.

Define `ResponseMetaInfo` structure of response information. Add
`WithResponseInfoHandler` client option which allows to set the response
info callback. The callback is called right after any response is received.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-09-27 14:42:16 +03:00 committed by Alex Vanin
parent 3844a3ac74
commit da89c2b71f
8 changed files with 139 additions and 0 deletions

View file

@ -43,6 +43,11 @@ func (c *clientImpl) GetBalance(ctx context.Context, owner *owner.ID, opts ...Ca
return nil, fmt.Errorf("transport error: %w", err) return nil, fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)

View file

@ -130,6 +130,11 @@ func (c *clientImpl) PutContainer(ctx context.Context, cnr *container.Container,
return nil, err return nil, err
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)
@ -166,6 +171,11 @@ func (c *clientImpl) GetContainer(ctx context.Context, id *cid.ID, opts ...CallO
return nil, fmt.Errorf("transport error: %w", err) return nil, fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)
@ -238,6 +248,11 @@ func (c *clientImpl) ListContainers(ctx context.Context, ownerID *owner.ID, opts
return nil, fmt.Errorf("transport error: %w", err) return nil, fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)
@ -292,6 +307,11 @@ func (c *clientImpl) DeleteContainer(ctx context.Context, id *cid.ID, opts ...Ca
return fmt.Errorf("transport error: %w", err) return fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return err
}
if err := v2signature.VerifyServiceMessage(resp); err != nil { if err := v2signature.VerifyServiceMessage(resp); err != nil {
return fmt.Errorf("can't verify response message: %w", err) return fmt.Errorf("can't verify response message: %w", err)
} }
@ -324,6 +344,11 @@ func (c *clientImpl) GetEACL(ctx context.Context, id *cid.ID, opts ...CallOption
return nil, fmt.Errorf("transport error: %w", err) return nil, fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)
@ -388,6 +413,11 @@ func (c *clientImpl) SetEACL(ctx context.Context, eacl *eacl.Table, opts ...Call
return fmt.Errorf("transport error: %w", err) return fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return fmt.Errorf("can't verify response message: %w", err) return fmt.Errorf("can't verify response message: %w", err)
@ -433,6 +463,11 @@ func (c *clientImpl) AnnounceContainerUsedSpace(
return fmt.Errorf("transport error: %w", err) return fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return fmt.Errorf("can't verify response message: %w", err) return fmt.Errorf("can't verify response message: %w", err)

View file

@ -67,6 +67,11 @@ func (c *clientImpl) EndpointInfo(ctx context.Context, opts ...CallOption) (*End
return nil, fmt.Errorf("transport error: %w", err) return nil, fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)
@ -105,6 +110,11 @@ func (c *clientImpl) NetworkInfo(ctx context.Context, opts ...CallOption) (*netm
return nil, fmt.Errorf("v2 NetworkInfo RPC failure: %w", err) return nil, fmt.Errorf("v2 NetworkInfo RPC failure: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("response message verification failed: %w", err) return nil, fmt.Errorf("response message verification failed: %w", err)

View file

@ -313,6 +313,11 @@ func (c *clientImpl) PutObject(ctx context.Context, p *PutObjectParams, opts ...
return nil, fmt.Errorf("closing the stream failed: %w", err) return nil, fmt.Errorf("closing the stream failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return nil, err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return nil, fmt.Errorf("response verification failed: %w", err) return nil, fmt.Errorf("response verification failed: %w", err)
@ -417,6 +422,11 @@ func (c *clientImpl) DeleteObject(ctx context.Context, p *DeleteObjectParams, op
return fmt.Errorf("sending the request failed: %w", err) return fmt.Errorf("sending the request failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return fmt.Errorf("response verification failed: %w", err) return fmt.Errorf("response verification failed: %w", err)
@ -623,6 +633,11 @@ loop:
return nil, fmt.Errorf("reading the response failed: %w", err) return nil, fmt.Errorf("reading the response failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return nil, err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return nil, fmt.Errorf("response verification failed: %w", err) return nil, fmt.Errorf("response verification failed: %w", err)
@ -781,6 +796,11 @@ func (c *clientImpl) GetObjectHeader(ctx context.Context, p *ObjectHeaderParams,
return nil, fmt.Errorf("sending the request failed: %w", err) return nil, fmt.Errorf("sending the request failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return nil, err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return nil, fmt.Errorf("response verification failed: %w", err) return nil, fmt.Errorf("response verification failed: %w", err)
@ -979,6 +999,11 @@ func (c *clientImpl) ObjectPayloadRangeData(ctx context.Context, p *RangeDataPar
return nil, fmt.Errorf("reading the response failed: %w", err) return nil, fmt.Errorf("reading the response failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return nil, err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return nil, fmt.Errorf("could not verify %T: %w", resp, err) return nil, fmt.Errorf("could not verify %T: %w", resp, err)
@ -1128,6 +1153,11 @@ func (c *clientImpl) objectPayloadRangeHash(ctx context.Context, p *RangeChecksu
return nil, fmt.Errorf("sending the request failed: %w", err) return nil, fmt.Errorf("sending the request failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return nil, err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return nil, fmt.Errorf("response verification failed: %w", err) return nil, fmt.Errorf("response verification failed: %w", err)
@ -1276,6 +1306,11 @@ func (c *clientImpl) SearchObject(ctx context.Context, p *SearchObjectParams, op
return nil, fmt.Errorf("reading the response failed: %w", err) return nil, fmt.Errorf("reading the response failed: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOpts, resp); err != nil {
return nil, err
}
// verify response structure // verify response structure
if err := signature.VerifyServiceMessage(resp); err != nil { if err := signature.VerifyServiceMessage(resp); err != nil {
return nil, fmt.Errorf("could not verify %T: %w", resp, err) return nil, fmt.Errorf("could not verify %T: %w", resp, err)

View file

@ -33,6 +33,8 @@ type (
key *ecdsa.PrivateKey key *ecdsa.PrivateKey
rawOpts []client.Option rawOpts []client.Option
cbRespInfo func(ResponseMetaInfo) error
} }
v2SessionReqInfo struct { v2SessionReqInfo struct {

View file

@ -77,6 +77,11 @@ func (c *clientImpl) AnnounceLocalTrust(ctx context.Context, prm AnnounceLocalTr
return nil, err return nil, err
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)
@ -152,6 +157,11 @@ func (c *clientImpl) AnnounceIntermediateTrust(ctx context.Context, prm Announce
return nil, err return nil, err
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)

37
pkg/client/response.go Normal file
View file

@ -0,0 +1,37 @@
package client
import (
"github.com/nspcc-dev/neofs-api-go/v2/session"
)
// ResponseMetaInfo groups meta information about any NeoFS API response.
type ResponseMetaInfo struct {
key []byte
}
// ResponderKey returns responder's public key in a binary format.
//
// Result must not be mutated.
func (x ResponseMetaInfo) ResponderKey() []byte {
return x.key
}
// WithResponseInfoHandler allows to specify handler of response meta information for the all Client operations.
// The handler is called right after the response is received. Client returns handler's error immediately.
func WithResponseInfoHandler(f func(ResponseMetaInfo) error) Option {
return func(opts *clientOptions) {
opts.cbRespInfo = f
}
}
func (c *clientImpl) handleResponseInfoV2(opts *callOptions, resp interface {
GetVerificationHeader() *session.ResponseVerificationHeader
}) error {
if c.opts.cbRespInfo == nil {
return nil
}
return c.opts.cbRespInfo(ResponseMetaInfo{
key: resp.GetVerificationHeader().GetBodySignature().GetKey(),
})
}

View file

@ -55,6 +55,11 @@ func (c *clientImpl) CreateSession(ctx context.Context, expiration uint64, opts
return nil, fmt.Errorf("transport error: %w", err) return nil, fmt.Errorf("transport error: %w", err)
} }
// handle response meta info
if err := c.handleResponseInfoV2(callOptions, resp); err != nil {
return nil, err
}
err = v2signature.VerifyServiceMessage(resp) err = v2signature.VerifyServiceMessage(resp)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't verify response message: %w", err) return nil, fmt.Errorf("can't verify response message: %w", err)