package object import ( "context" "errors" "fmt" clientcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" netmapCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" 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-sdk-go/netmap" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" ) type ClientConstructor interface { Get(clientcore.NodeInfo) (clientcore.MultiAddressClient, error) } // RemoteReader represents utility for getting // the object from a remote host. type RemoteReader struct { keyStorage *util.KeyStorage clientCache ClientConstructor } // RemoteRequestPrm groups remote operation parameters. type RemoteRequestPrm struct { addr oid.Address raw bool node netmap.NodeInfo } const remoteOpTTL = 1 var ErrNotFound = errors.New("object header not found") // NewRemoteReader creates, initializes and returns new RemoteHeader instance. func NewRemoteReader(keyStorage *util.KeyStorage, cache ClientConstructor) *RemoteReader { return &RemoteReader{ keyStorage: keyStorage, clientCache: cache, } } // WithNodeInfo sets information about the remote node. func (p *RemoteRequestPrm) WithNodeInfo(v netmap.NodeInfo) *RemoteRequestPrm { if p != nil { p.node = v } return p } // WithObjectAddress sets object address. func (p *RemoteRequestPrm) WithObjectAddress(v oid.Address) *RemoteRequestPrm { if p != nil { p.addr = v } return p } func (p *RemoteRequestPrm) WithRaw(v bool) *RemoteRequestPrm { if p != nil { p.raw = v } return p } // Head requests object header from the remote node. func (h *RemoteReader) Head(ctx context.Context, prm *RemoteRequestPrm) (*objectSDK.Object, error) { key, err := h.keyStorage.GetKey(nil) if err != nil { return nil, fmt.Errorf("(%T) could not receive private key: %w", h, err) } var info clientcore.NodeInfo err = clientcore.NodeInfoFromRawNetmapElement(&info, netmapCore.Node(prm.node)) if err != nil { return nil, fmt.Errorf("parse client node info: %w", err) } c, err := h.clientCache.Get(info) if err != nil { return nil, fmt.Errorf("(%T) could not create SDK client %s: %w", h, info.AddressGroup(), err) } var headPrm internalclient.HeadObjectPrm headPrm.SetClient(c) headPrm.SetPrivateKey(key) headPrm.SetAddress(prm.addr) headPrm.SetTTL(remoteOpTTL) if prm.raw { headPrm.SetRawFlag() } res, err := internalclient.HeadObject(ctx, headPrm) if err != nil { return nil, fmt.Errorf("(%T) could not head object in %s: %w", h, info.AddressGroup(), err) } return res.Header(), nil } func (h *RemoteReader) Get(ctx context.Context, prm *RemoteRequestPrm) (*objectSDK.Object, error) { key, err := h.keyStorage.GetKey(nil) if err != nil { return nil, fmt.Errorf("(%T) could not receive private key: %w", h, err) } var info clientcore.NodeInfo err = clientcore.NodeInfoFromRawNetmapElement(&info, netmapCore.Node(prm.node)) if err != nil { return nil, fmt.Errorf("parse client node info: %w", err) } c, err := h.clientCache.Get(info) if err != nil { return nil, fmt.Errorf("(%T) could not create SDK client %s: %w", h, info.AddressGroup(), err) } var getPrm internalclient.GetObjectPrm getPrm.SetClient(c) getPrm.SetPrivateKey(key) getPrm.SetAddress(prm.addr) getPrm.SetTTL(remoteOpTTL) if prm.raw { getPrm.SetRawFlag() } res, err := internalclient.GetObject(ctx, getPrm) if err != nil { return nil, fmt.Errorf("(%T) could not head object in %s: %w", h, info.AddressGroup(), err) } return res.Object(), nil }