package getsvc import ( "context" "crypto/ecdsa" "errors" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" coreclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/util" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" ) type epochSource interface { Epoch() (uint64, error) } type traverserGenerator interface { GenerateTraverser(cid.ID, *oid.ID, uint64) (*placement.Traverser, error) } type keyStorage interface { GetKey(info *util.SessionInfo) (*ecdsa.PrivateKey, error) } type localStorageEngine interface { Head(ctx context.Context, p engine.HeadPrm) (engine.HeadRes, error) GetRange(ctx context.Context, p engine.RngPrm) (engine.RngRes, error) Get(ctx context.Context, p engine.GetPrm) (engine.GetRes, error) } type clientConstructor interface { Get(client.NodeInfo) (client.MultiAddressClient, error) } type remoteStorageConstructor interface { Get(client.NodeInfo) (remoteStorage, error) } type multiclientRemoteStorageConstructor struct { clientConstructor clientConstructor } func (c *multiclientRemoteStorageConstructor) Get(info client.NodeInfo) (remoteStorage, error) { clt, err := c.clientConstructor.Get(info) if err != nil { return nil, err } return &multiaddressRemoteStorage{ client: clt, }, nil } type remoteStorage interface { GetObject(context.Context, *execCtx, client.NodeInfo) (*objectSDK.Object, error) } type localStorage interface { Head(ctx context.Context, address oid.Address, isRaw bool) (*objectSDK.Object, error) Range(ctx context.Context, address oid.Address, rng *objectSDK.Range) (*objectSDK.Object, error) Get(ctx context.Context, address oid.Address) (*objectSDK.Object, error) } type engineLocalStorage struct { engine localStorageEngine } func (s *engineLocalStorage) Head(ctx context.Context, address oid.Address, isRaw bool) (*objectSDK.Object, error) { var headPrm engine.HeadPrm headPrm.WithAddress(address) headPrm.WithRaw(isRaw) r, err := s.engine.Head(ctx, headPrm) if err != nil { return nil, err } return r.Header(), nil } func (s *engineLocalStorage) Range(ctx context.Context, address oid.Address, rng *objectSDK.Range) (*objectSDK.Object, error) { var getRange engine.RngPrm getRange.WithAddress(address) getRange.WithPayloadRange(rng) r, err := s.engine.GetRange(ctx, getRange) if err != nil { return nil, err } return r.Object(), nil } func (s *engineLocalStorage) Get(ctx context.Context, address oid.Address) (*objectSDK.Object, error) { var getPrm engine.GetPrm getPrm.WithAddress(address) r, err := s.engine.Get(ctx, getPrm) if err != nil { return nil, err } return r.Object(), nil } type multiaddressRemoteStorage struct { client coreclient.MultiAddressClient } func (s *multiaddressRemoteStorage) GetObject(ctx context.Context, exec *execCtx, info coreclient.NodeInfo) (*objectSDK.Object, error) { if exec.isForwardingEnabled() { return exec.prm.forwarder(ctx, info, s.client) } key, err := exec.key() if err != nil { return nil, err } if exec.headOnly() { return s.getHeadOnly(ctx, exec, key) } // we don't specify payload writer because we accumulate // the object locally (even huge). if rng := exec.ctxRange(); rng != nil { // Current spec allows other storage node to deny access, // fallback to GET here. return s.getRange(ctx, exec, key, rng) } return s.get(ctx, exec, key) } func (s *multiaddressRemoteStorage) getRange(ctx context.Context, exec *execCtx, key *ecdsa.PrivateKey, rng *object.Range) (*object.Object, error) { var prm internalclient.PayloadRangePrm prm.SetClient(s.client) prm.SetTTL(exec.prm.common.TTL()) prm.SetNetmapEpoch(exec.curProcEpoch) prm.SetAddress(exec.address()) prm.SetPrivateKey(key) prm.SetSessionToken(exec.prm.common.SessionToken()) prm.SetBearerToken(exec.prm.common.BearerToken()) prm.SetXHeaders(exec.prm.common.XHeaders()) prm.SetRange(rng) if exec.isRaw() { prm.SetRawFlag() } res, err := internalclient.PayloadRange(ctx, prm) if err != nil { var errAccessDenied *apistatus.ObjectAccessDenied if errors.As(err, &errAccessDenied) { obj, err := s.get(ctx, exec, key) if err != nil { return nil, err } payload := obj.Payload() from := rng.GetOffset() to := from + rng.GetLength() if pLen := uint64(len(payload)); to < from || pLen < from || pLen < to { return nil, new(apistatus.ObjectOutOfRange) } return payloadOnlyObject(payload[from:to]), nil } return nil, err } return payloadOnlyObject(res.PayloadRange()), nil } func (s *multiaddressRemoteStorage) getHeadOnly(ctx context.Context, exec *execCtx, key *ecdsa.PrivateKey) (*object.Object, error) { var prm internalclient.HeadObjectPrm prm.SetClient(s.client) prm.SetTTL(exec.prm.common.TTL()) prm.SetNetmapEpoch(exec.curProcEpoch) prm.SetAddress(exec.address()) prm.SetPrivateKey(key) prm.SetSessionToken(exec.prm.common.SessionToken()) prm.SetBearerToken(exec.prm.common.BearerToken()) prm.SetXHeaders(exec.prm.common.XHeaders()) if exec.isRaw() { prm.SetRawFlag() } res, err := internalclient.HeadObject(ctx, prm) if err != nil { return nil, err } return res.Header(), nil } func (s *multiaddressRemoteStorage) get(ctx context.Context, exec *execCtx, key *ecdsa.PrivateKey) (*object.Object, error) { var prm internalclient.GetObjectPrm prm.SetClient(s.client) prm.SetTTL(exec.prm.common.TTL()) prm.SetNetmapEpoch(exec.curProcEpoch) prm.SetAddress(exec.address()) prm.SetPrivateKey(key) prm.SetSessionToken(exec.prm.common.SessionToken()) prm.SetBearerToken(exec.prm.common.BearerToken()) prm.SetXHeaders(exec.prm.common.XHeaders()) if exec.isRaw() { prm.SetRawFlag() } res, err := internalclient.GetObject(ctx, prm) if err != nil { return nil, err } return res.Object(), nil }