2020-09-26 07:54:03 +00:00
|
|
|
package getsvc
|
|
|
|
|
|
|
|
import (
|
2021-04-29 12:18:29 +00:00
|
|
|
"context"
|
2020-12-08 16:18:24 +00:00
|
|
|
"crypto/sha256"
|
2021-05-18 08:12:51 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2020-12-08 16:18:24 +00:00
|
|
|
"hash"
|
2021-04-29 12:18:29 +00:00
|
|
|
"sync"
|
2020-12-08 16:18:24 +00:00
|
|
|
|
2023-03-07 13:38:26 +00:00
|
|
|
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
|
|
|
|
objectSvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object"
|
|
|
|
getsvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/get"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/util"
|
|
|
|
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
|
|
versionSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
|
|
|
|
"git.frostfs.info/TrueCloudLab/tzhash/tz"
|
2020-09-26 07:54:03 +00:00
|
|
|
)
|
|
|
|
|
2021-04-29 12:18:29 +00:00
|
|
|
var errWrongMessageSeq = errors.New("incorrect message sequence")
|
|
|
|
|
2020-12-02 23:45:25 +00:00
|
|
|
func (s *Service) toPrm(req *objectV2.GetRequest, stream objectSvc.GetObjectStream) (*getsvc.Prm, error) {
|
2022-05-31 17:00:41 +00:00
|
|
|
body := req.GetBody()
|
|
|
|
|
|
|
|
addrV2 := body.GetAddress()
|
|
|
|
if addrV2 == nil {
|
|
|
|
return nil, errors.New("missing object address")
|
|
|
|
}
|
|
|
|
|
|
|
|
var addr oid.Address
|
|
|
|
|
|
|
|
err := addr.ReadFromV2(*addrV2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid object address: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-01-12 14:55:02 +00:00
|
|
|
commonPrm, err := util.CommonPrmFromV2(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-07-15 06:55:53 +00:00
|
|
|
streamWrapper := &streamObjectWriter{stream}
|
|
|
|
|
2020-12-02 23:45:25 +00:00
|
|
|
p := new(getsvc.Prm)
|
2021-10-26 13:02:46 +00:00
|
|
|
p.SetCommonParameters(commonPrm)
|
2020-12-02 23:45:25 +00:00
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
p.WithAddress(addr)
|
2020-12-07 17:49:47 +00:00
|
|
|
p.WithRawFlag(body.GetRaw())
|
2022-07-15 06:55:53 +00:00
|
|
|
p.SetObjectWriter(streamWrapper)
|
2020-12-02 23:45:25 +00:00
|
|
|
|
2021-04-29 12:18:29 +00:00
|
|
|
if !commonPrm.LocalOnly() {
|
2023-03-31 14:38:38 +00:00
|
|
|
forwarder := &getRequestForwarder{
|
|
|
|
OnceResign: &sync.Once{},
|
|
|
|
OnceHeaderSending: &sync.Once{},
|
|
|
|
GlobalProgress: 0,
|
|
|
|
KeyStorage: s.keyStorage,
|
|
|
|
Request: req,
|
|
|
|
Stream: streamWrapper,
|
|
|
|
}
|
2022-11-30 17:36:34 +00:00
|
|
|
|
2022-03-03 14:19:05 +00:00
|
|
|
p.SetRequestForwarder(groupAddressRequestForwarder(func(addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
|
2023-03-31 14:38:38 +00:00
|
|
|
return forwarder.forward(stream.Context(), addr, c, pubkey)
|
2021-06-22 12:08:17 +00:00
|
|
|
}))
|
2021-04-29 12:18:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 23:45:25 +00:00
|
|
|
return p, nil
|
2020-09-26 07:54:03 +00:00
|
|
|
}
|
|
|
|
|
2020-12-07 17:49:47 +00:00
|
|
|
func (s *Service) toRangePrm(req *objectV2.GetRangeRequest, stream objectSvc.GetObjectRangeStream) (*getsvc.RangePrm, error) {
|
2022-05-31 17:00:41 +00:00
|
|
|
body := req.GetBody()
|
|
|
|
|
|
|
|
addrV2 := body.GetAddress()
|
|
|
|
if addrV2 == nil {
|
|
|
|
return nil, errors.New("missing object address")
|
|
|
|
}
|
|
|
|
|
|
|
|
var addr oid.Address
|
|
|
|
|
|
|
|
err := addr.ReadFromV2(*addrV2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid object address: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-01-12 14:55:02 +00:00
|
|
|
commonPrm, err := util.CommonPrmFromV2(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-07 17:49:47 +00:00
|
|
|
p := new(getsvc.RangePrm)
|
2021-10-26 13:02:46 +00:00
|
|
|
p.SetCommonParameters(commonPrm)
|
2020-12-07 17:49:47 +00:00
|
|
|
|
2022-07-15 06:55:53 +00:00
|
|
|
streamWrapper := &streamObjectRangeWriter{stream}
|
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
p.WithAddress(addr)
|
2020-12-07 17:49:47 +00:00
|
|
|
p.WithRawFlag(body.GetRaw())
|
2022-07-15 06:55:53 +00:00
|
|
|
p.SetChunkWriter(streamWrapper)
|
2022-03-03 14:19:05 +00:00
|
|
|
p.SetRange(object.NewRangeFromV2(body.GetRange()))
|
2020-12-07 17:49:47 +00:00
|
|
|
|
2022-11-24 14:28:50 +00:00
|
|
|
err = p.Validate()
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("request params validation: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-04-29 12:18:29 +00:00
|
|
|
if !commonPrm.LocalOnly() {
|
2023-03-31 14:41:42 +00:00
|
|
|
forwarder := &getRangeRequestForwarder{
|
|
|
|
OnceResign: &sync.Once{},
|
|
|
|
GlobalProgress: 0,
|
|
|
|
KeyStorage: s.keyStorage,
|
|
|
|
Request: req,
|
|
|
|
Stream: streamWrapper,
|
2021-10-26 12:07:28 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 14:19:05 +00:00
|
|
|
p.SetRequestForwarder(groupAddressRequestForwarder(func(addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
|
2023-03-31 14:41:42 +00:00
|
|
|
return forwarder.forward(stream.Context(), addr, c, pubkey)
|
2021-06-22 12:08:17 +00:00
|
|
|
}))
|
2021-04-29 12:18:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-07 17:49:47 +00:00
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
2020-12-08 16:18:24 +00:00
|
|
|
func (s *Service) toHashRangePrm(req *objectV2.GetRangeHashRequest) (*getsvc.RangeHashPrm, error) {
|
2022-05-31 17:00:41 +00:00
|
|
|
body := req.GetBody()
|
|
|
|
|
|
|
|
addrV2 := body.GetAddress()
|
|
|
|
if addrV2 == nil {
|
|
|
|
return nil, errors.New("missing object address")
|
|
|
|
}
|
|
|
|
|
|
|
|
var addr oid.Address
|
|
|
|
|
|
|
|
err := addr.ReadFromV2(*addrV2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid object address: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-01-12 14:55:02 +00:00
|
|
|
commonPrm, err := util.CommonPrmFromV2(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-08 16:18:24 +00:00
|
|
|
p := new(getsvc.RangeHashPrm)
|
2021-10-26 13:02:46 +00:00
|
|
|
p.SetCommonParameters(commonPrm)
|
2020-12-08 16:18:24 +00:00
|
|
|
|
2022-05-31 17:00:41 +00:00
|
|
|
p.WithAddress(addr)
|
2020-12-08 16:18:24 +00:00
|
|
|
|
2022-12-21 16:32:08 +00:00
|
|
|
if tok := commonPrm.SessionToken(); tok != nil {
|
|
|
|
signerKey, err := s.keyStorage.GetKey(&util.SessionInfo{
|
|
|
|
ID: tok.ID(),
|
|
|
|
Owner: tok.Issuer(),
|
|
|
|
})
|
|
|
|
if err != nil && errors.As(err, new(apistatus.SessionTokenNotFound)) {
|
|
|
|
commonPrm.ForgetTokens()
|
|
|
|
signerKey, err = s.keyStorage.GetKey(nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("fetching session key: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
p.WithCachedSignerKey(signerKey)
|
|
|
|
}
|
|
|
|
|
2020-12-08 16:18:24 +00:00
|
|
|
rngsV2 := body.GetRanges()
|
2022-03-15 12:11:35 +00:00
|
|
|
rngs := make([]object.Range, len(rngsV2))
|
2020-12-08 16:18:24 +00:00
|
|
|
|
|
|
|
for i := range rngsV2 {
|
2022-03-15 12:11:35 +00:00
|
|
|
rngs[i] = *object.NewRangeFromV2(&rngsV2[i])
|
2020-12-08 16:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p.SetRangeList(rngs)
|
2021-01-11 13:50:04 +00:00
|
|
|
p.SetSalt(body.GetSalt())
|
2020-12-08 16:18:24 +00:00
|
|
|
|
|
|
|
switch t := body.GetType(); t {
|
|
|
|
default:
|
2021-05-18 08:12:51 +00:00
|
|
|
return nil, fmt.Errorf("unknown checksum type %v", t)
|
2020-12-08 16:18:24 +00:00
|
|
|
case refs.SHA256:
|
|
|
|
p.SetHashGenerator(func() hash.Hash {
|
|
|
|
return sha256.New()
|
|
|
|
})
|
|
|
|
case refs.TillichZemor:
|
|
|
|
p.SetHashGenerator(func() hash.Hash {
|
|
|
|
return tz.New()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
2020-12-09 10:32:33 +00:00
|
|
|
type headResponseWriter struct {
|
|
|
|
mainOnly bool
|
|
|
|
|
|
|
|
body *objectV2.HeadResponseBody
|
|
|
|
}
|
|
|
|
|
2023-03-09 08:02:27 +00:00
|
|
|
func (w *headResponseWriter) WriteHeader(_ context.Context, hdr *object.Object) error {
|
2020-12-09 10:32:33 +00:00
|
|
|
if w.mainOnly {
|
|
|
|
w.body.SetHeaderPart(toShortObjectHeader(hdr))
|
|
|
|
} else {
|
|
|
|
w.body.SetHeaderPart(toFullObjectHeader(hdr))
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-04-29 12:18:29 +00:00
|
|
|
func (s *Service) toHeadPrm(ctx context.Context, req *objectV2.HeadRequest, resp *objectV2.HeadResponse) (*getsvc.HeadPrm, error) {
|
2022-05-31 17:00:41 +00:00
|
|
|
body := req.GetBody()
|
|
|
|
|
|
|
|
addrV2 := body.GetAddress()
|
|
|
|
if addrV2 == nil {
|
|
|
|
return nil, errors.New("missing object address")
|
|
|
|
}
|
|
|
|
|
|
|
|
var objAddr oid.Address
|
|
|
|
|
|
|
|
err := objAddr.ReadFromV2(*addrV2)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid object address: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-01-12 14:55:02 +00:00
|
|
|
commonPrm, err := util.CommonPrmFromV2(req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-12-09 10:32:33 +00:00
|
|
|
p := new(getsvc.HeadPrm)
|
2021-10-26 13:02:46 +00:00
|
|
|
p.SetCommonParameters(commonPrm)
|
2020-12-09 10:32:33 +00:00
|
|
|
|
2021-11-01 08:35:33 +00:00
|
|
|
p.WithAddress(objAddr)
|
2020-12-09 10:32:33 +00:00
|
|
|
p.WithRawFlag(body.GetRaw())
|
|
|
|
p.SetHeaderWriter(&headResponseWriter{
|
|
|
|
mainOnly: body.GetMainOnly(),
|
|
|
|
body: resp.GetBody(),
|
|
|
|
})
|
|
|
|
|
2023-03-21 14:53:09 +00:00
|
|
|
if commonPrm.LocalOnly() {
|
|
|
|
return p, nil
|
|
|
|
}
|
2021-04-29 12:18:29 +00:00
|
|
|
|
2023-03-31 13:30:46 +00:00
|
|
|
forwarder := &headRequestForwarder{
|
|
|
|
Request: req,
|
|
|
|
Response: resp,
|
|
|
|
OnceResign: &sync.Once{},
|
|
|
|
ObjectAddr: objAddr,
|
|
|
|
KeyStorage: s.keyStorage,
|
|
|
|
}
|
2021-04-29 12:18:29 +00:00
|
|
|
|
2023-03-21 14:53:09 +00:00
|
|
|
p.SetRequestForwarder(groupAddressRequestForwarder(func(addr network.Address, c client.MultiAddressClient, pubkey []byte) (*object.Object, error) {
|
2023-03-31 13:30:46 +00:00
|
|
|
return forwarder.forward(ctx, addr, c, pubkey)
|
2023-03-21 14:53:09 +00:00
|
|
|
}))
|
2021-04-29 12:18:29 +00:00
|
|
|
|
2020-12-09 10:32:33 +00:00
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
2022-03-03 14:19:05 +00:00
|
|
|
func splitInfoResponse(info *object.SplitInfo) *objectV2.GetResponse {
|
2020-12-02 23:45:25 +00:00
|
|
|
resp := new(objectV2.GetResponse)
|
|
|
|
|
|
|
|
body := new(objectV2.GetResponseBody)
|
|
|
|
resp.SetBody(body)
|
|
|
|
|
|
|
|
body.SetObjectPart(info.ToV2())
|
|
|
|
|
|
|
|
return resp
|
2020-09-26 07:54:03 +00:00
|
|
|
}
|
2020-12-07 17:49:47 +00:00
|
|
|
|
2022-03-03 14:19:05 +00:00
|
|
|
func splitInfoRangeResponse(info *object.SplitInfo) *objectV2.GetRangeResponse {
|
2020-12-07 17:49:47 +00:00
|
|
|
resp := new(objectV2.GetRangeResponse)
|
|
|
|
|
|
|
|
body := new(objectV2.GetRangeResponseBody)
|
|
|
|
resp.SetBody(body)
|
|
|
|
|
|
|
|
body.SetRangePart(info.ToV2())
|
|
|
|
|
|
|
|
return resp
|
|
|
|
}
|
2020-12-08 16:18:24 +00:00
|
|
|
|
2022-03-03 14:19:05 +00:00
|
|
|
func setSplitInfoHeadResponse(info *object.SplitInfo, resp *objectV2.HeadResponse) {
|
2020-12-09 10:32:33 +00:00
|
|
|
resp.GetBody().SetHeaderPart(info.ToV2())
|
|
|
|
}
|
|
|
|
|
2020-12-08 16:18:24 +00:00
|
|
|
func toHashResponse(typ refs.ChecksumType, res *getsvc.RangeHashRes) *objectV2.GetRangeHashResponse {
|
|
|
|
resp := new(objectV2.GetRangeHashResponse)
|
|
|
|
|
|
|
|
body := new(objectV2.GetRangeHashResponseBody)
|
|
|
|
resp.SetBody(body)
|
|
|
|
|
|
|
|
body.SetType(typ)
|
|
|
|
body.SetHashList(res.Hashes())
|
|
|
|
|
|
|
|
return resp
|
|
|
|
}
|
2020-12-09 10:32:33 +00:00
|
|
|
|
|
|
|
func toFullObjectHeader(hdr *object.Object) objectV2.GetHeaderPart {
|
|
|
|
obj := hdr.ToV2()
|
|
|
|
|
|
|
|
hs := new(objectV2.HeaderWithSignature)
|
|
|
|
hs.SetHeader(obj.GetHeader())
|
|
|
|
hs.SetSignature(obj.GetSignature())
|
|
|
|
|
|
|
|
return hs
|
|
|
|
}
|
|
|
|
|
|
|
|
func toShortObjectHeader(hdr *object.Object) objectV2.GetHeaderPart {
|
|
|
|
hdrV2 := hdr.ToV2().GetHeader()
|
|
|
|
|
|
|
|
sh := new(objectV2.ShortHeader)
|
|
|
|
sh.SetOwnerID(hdrV2.GetOwnerID())
|
|
|
|
sh.SetCreationEpoch(hdrV2.GetCreationEpoch())
|
|
|
|
sh.SetPayloadLength(hdrV2.GetPayloadLength())
|
|
|
|
sh.SetVersion(hdrV2.GetVersion())
|
|
|
|
sh.SetObjectType(hdrV2.GetObjectType())
|
2020-12-23 09:35:36 +00:00
|
|
|
sh.SetHomomorphicHash(hdrV2.GetHomomorphicHash())
|
|
|
|
sh.SetPayloadHash(hdrV2.GetPayloadHash())
|
2020-12-09 10:32:33 +00:00
|
|
|
|
|
|
|
return sh
|
|
|
|
}
|
2021-06-22 12:08:17 +00:00
|
|
|
|
2022-03-03 14:19:05 +00:00
|
|
|
func groupAddressRequestForwarder(f func(network.Address, client.MultiAddressClient, []byte) (*object.Object, error)) getsvc.RequestForwarder {
|
|
|
|
return func(info client.NodeInfo, c client.MultiAddressClient) (*object.Object, error) {
|
2021-06-22 12:08:17 +00:00
|
|
|
var (
|
|
|
|
firstErr error
|
2022-03-03 14:19:05 +00:00
|
|
|
res *object.Object
|
2021-09-28 06:02:02 +00:00
|
|
|
|
|
|
|
key = info.PublicKey()
|
2021-06-22 12:08:17 +00:00
|
|
|
)
|
|
|
|
|
2021-09-28 04:46:10 +00:00
|
|
|
info.AddressGroup().IterateAddresses(func(addr network.Address) (stop bool) {
|
2021-06-22 12:08:17 +00:00
|
|
|
var err error
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
stop = err == nil
|
|
|
|
|
|
|
|
if stop || firstErr == nil {
|
|
|
|
firstErr = err
|
|
|
|
}
|
|
|
|
|
|
|
|
// would be nice to log otherwise
|
|
|
|
}()
|
|
|
|
|
2021-09-28 06:02:02 +00:00
|
|
|
res, err = f(addr, c, key)
|
2021-06-22 12:08:17 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
})
|
|
|
|
|
|
|
|
return res, firstErr
|
|
|
|
}
|
|
|
|
}
|
2022-07-05 21:09:30 +00:00
|
|
|
|
|
|
|
func writeCurrentVersion(metaHdr *session.RequestMetaHeader) {
|
|
|
|
versionV2 := new(refs.Version)
|
|
|
|
|
|
|
|
apiVersion := versionSDK.Current()
|
|
|
|
apiVersion.WriteToV2(versionV2)
|
|
|
|
|
|
|
|
metaHdr.SetVersion(versionV2)
|
|
|
|
}
|
2022-07-07 15:02:07 +00:00
|
|
|
|
|
|
|
func checkStatus(stV2 *status.Status) error {
|
|
|
|
if !status.IsSuccess(stV2.Code()) {
|
|
|
|
st := apistatus.FromStatusV2(stV2)
|
|
|
|
return apistatus.ErrFromStatus(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2022-11-30 17:36:34 +00:00
|
|
|
|
|
|
|
func chunkToSend(global, local int, chunk []byte) []byte {
|
|
|
|
if global == local {
|
|
|
|
return chunk
|
|
|
|
}
|
|
|
|
|
|
|
|
if local+len(chunk) <= global {
|
|
|
|
// chunk has already been sent
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return chunk[global-local:]
|
|
|
|
}
|