package getsvc import ( "context" "errors" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" clientcore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" objectSvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object" getsvc "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/get" objutil "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/util" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "go.uber.org/zap" ) // Service implements Get operation of Object service v2. type Service struct { *cfg } // Option represents Service constructor option. type Option func(*cfg) type epochSource interface { Epoch() (uint64, error) } type clientSource interface { Get(info clientcore.NodeInfo) (clientcore.MultiAddressClient, error) } type cfg struct { svc *getsvc.Service keyStorage *objutil.KeyStorage epochSource epochSource clientSource clientSource netmapSource netmap.Source announcedKeys netmap.AnnouncedKeys contSource container.Source log *logger.Logger } // NewService constructs Service instance from provided options. func NewService(opts ...Option) *Service { c := new(cfg) for i := range opts { opts[i](c) } return &Service{ cfg: c, } } // Get calls internal service and returns v2 object stream. func (s *Service) Get(req *objectV2.GetRequest, stream objectSvc.GetObjectStream) error { p, err := s.toPrm(req, stream) if err != nil { return err } err = s.svc.Get(stream.Context(), *p) var splitErr *objectSDK.SplitInfoError switch { case errors.As(err, &splitErr): return stream.Send(splitInfoResponse(splitErr.SplitInfo())) default: return err } } // GetRange calls internal service and returns v2 payload range stream. func (s *Service) GetRange(req *objectV2.GetRangeRequest, stream objectSvc.GetObjectRangeStream) error { p, err := s.toRangePrm(req, stream) if err != nil { return err } err = s.svc.GetRange(stream.Context(), *p) var splitErr *objectSDK.SplitInfoError switch { case errors.As(err, &splitErr): return stream.Send(splitInfoRangeResponse(splitErr.SplitInfo())) default: return err } } // Head serves ForstFS API v2 compatible HEAD requests. func (s *Service) Head(ctx context.Context, req *objectV2.HeadRequest) (*objectV2.HeadResponse, error) { resp := new(objectV2.HeadResponse) resp.SetBody(new(objectV2.HeadResponseBody)) p, err := s.toHeadPrm(req, resp) if err != nil { return nil, err } err = s.svc.Head(ctx, *p) var splitErr *objectSDK.SplitInfoError if errors.As(err, &splitErr) { setSplitInfoHeadResponse(splitErr.SplitInfo(), resp) err = nil } return resp, err } func WithInternalService(v *getsvc.Service) Option { return func(c *cfg) { c.svc = v } } // WithKeyStorage returns option to set local private key storage. func WithKeyStorage(ks *objutil.KeyStorage) Option { return func(c *cfg) { c.keyStorage = ks } } func WithEpochSource(es epochSource) Option { return func(c *cfg) { c.epochSource = es } } func WithClientSource(cs clientSource) Option { return func(c *cfg) { c.clientSource = cs } } func WithNetmapSource(ns netmap.Source) Option { return func(c *cfg) { c.netmapSource = ns } } func WithNetmapAnnouncedKeys(ak netmap.AnnouncedKeys) Option { return func(c *cfg) { c.announcedKeys = ak } } func WithContainerSource(cs container.Source) Option { return func(c *cfg) { c.contSource = cs } } func WithLogger(l *logger.Logger) Option { return func(c *cfg) { c.log = &logger.Logger{Logger: l.With(zap.String("component", "Object.Get V2 service"))} } }