[#323] client: Refactor `object.Hash`

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
remotes/fyrchik/maintenance
Evgenii Stratonikov 2022-08-23 20:51:05 +03:00 committed by fyrchik
parent 0236b03fa7
commit 8c5333ea55
2 changed files with 80 additions and 31 deletions

View File

@ -65,6 +65,20 @@ func (x prmCommonMeta) writeToMetaHeader(h *v2session.RequestMetaHeader) {
}
}
func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
if len(xHeaders) == 0 {
return
}
hs := make([]v2session.XHeader, len(xHeaders)/2)
for i := 0; i < len(xHeaders); i += 2 {
hs[i].SetKey(xHeaders[i])
hs[i].SetValue(xHeaders[i+1])
}
h.SetXHeaders(hs)
}
// panic messages.
const (
panicMsgMissingContext = "missing context"
@ -108,11 +122,7 @@ type contextCall struct {
statusRes resCommon
// request to be signed with a key and sent
req interface {
GetMetaHeader() *v2session.RequestMetaHeader
SetMetaHeader(*v2session.RequestMetaHeader)
SetVerificationHeader(*v2session.RequestVerificationHeader)
}
req request
// function to send a request (unary) and receive a response
call func() (responseV2, error)
@ -130,6 +140,12 @@ type contextCall struct {
result func(v2 responseV2)
}
type request interface {
GetMetaHeader() *v2session.RequestMetaHeader
SetMetaHeader(*v2session.RequestMetaHeader)
SetVerificationHeader(*v2session.RequestVerificationHeader)
}
// sets needed fields of the request meta header.
func (x contextCall) prepareRequest() {
meta := x.req.GetMetaHeader()
@ -153,6 +169,25 @@ func (x contextCall) prepareRequest() {
x.meta.writeToMetaHeader(meta)
}
func (c *Client) prepareRequest(req request, meta *v2session.RequestMetaHeader) {
ttl := meta.GetTTL()
if ttl == 0 {
ttl = 2
}
verV2 := meta.GetVersion()
if verV2 == nil {
verV2 = new(refs.Version)
version.Current().WriteToV2(verV2)
}
meta.SetTTL(ttl)
meta.SetVersion(verV2)
meta.SetNetworkMagic(c.prm.netMagic)
req.SetMetaHeader(meta)
}
// prepares, signs and writes the request. Result means success.
// If failed, contextCall.err contains the reason.
func (x *contextCall) writeRequest() bool {
@ -222,6 +257,20 @@ func (x *contextCall) processResponse() bool {
return successfulStatus
}
// processResponse verifies response signature and converts status to an error if needed.
func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) {
err := signature.VerifyServiceMessage(resp)
if err != nil {
return nil, fmt.Errorf("invalid response signature: %w", err)
}
st := apistatus.FromStatusV2(resp.GetMetaHeader().GetStatus())
if c.prm.resolveNeoFSErrors {
return st, apistatus.ErrFromStatus(st)
}
return st, nil
}
// reads response (if rResp is set) and processes it. Result means success.
// If failed, contextCall.err (or statusRes if resolveAPIFailures is set) contains the reason.
func (x *contextCall) readResponse() bool {

View File

@ -2,6 +2,7 @@ package client
import (
"context"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/acl"
v2object "github.com/nspcc-dev/neofs-api-go/v2/object"
@ -9,7 +10,9 @@ import (
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"
"github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
@ -117,7 +120,7 @@ func (x *PrmObjectHash) WithXHeaders(hs ...string) {
panic("slice of X-Headers with odd length")
}
prmCommonMeta{xHeaders: hs}.writeToMetaHeader(&x.meta)
writeXHeadersToMeta(hs, &x.meta)
}
// ResObjectHash groups resulting values of ObjectHash operation.
@ -166,43 +169,40 @@ func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectH
panic("missing ranges")
}
// form request body
prm.body.SetAddress(&prm.addr)
// ranges and salt are already by prm setters
if prm.tillichZemor {
prm.body.SetType(v2refs.TillichZemor)
} else {
prm.body.SetType(v2refs.SHA256)
}
// form request
var req v2object.GetRangeHashRequest
c.prepareRequest(&req, &prm.meta)
req.SetBody(&prm.body)
req.SetMetaHeader(&prm.meta)
// init call context
var (
cc contextCall
res ResObjectHash
)
c.initCallContext(&cc)
cc.req = &req
cc.statusRes = &res
cc.call = func() (responseV2, error) {
return rpcapi.HashObjectRange(&c.c, &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
res.checksums = r.(*v2object.GetRangeHashResponse).GetBody().GetHashList()
if len(res.checksums) == 0 {
cc.err = newErrMissingResponseField("hash list")
}
err := signature.SignServiceMessage(&c.prm.key, req)
if err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
// process call
if !cc.processCall() {
return nil, cc.err
resp, err := rpcapi.HashObjectRange(&c.c, &req, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("write request: %w", err)
}
var res ResObjectHash
res.st, err = c.processResponse(resp)
if err != nil {
return nil, err
}
if !apistatus.IsSuccessful(res.st) {
return &res, nil
}
res.checksums = resp.GetBody().GetHashList()
if len(res.checksums) == 0 {
return nil, newErrMissingResponseField("hash list")
}
return &res, nil