package getsvc import ( "context" "errors" 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" objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" 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 clientSource interface { Get(info clientcore.NodeInfo) (clientcore.MultiAddressClient, error) } type cfg struct { svc *getsvc.Service keyStorage *objutil.KeyStorage clientSource clientSource netmapSource netmap.Source announcedKeys netmap.AnnouncedKeys contSource container.Source log *logger.Logger } // NewService constructs Service instance from provided options. func NewService(svc *getsvc.Service, keyStorage *objutil.KeyStorage, clientSource clientSource, netmapSource netmap.Source, announcedKeys netmap.AnnouncedKeys, contSource container.Source, opts ...Option, ) *Service { c := &cfg{ svc: svc, keyStorage: keyStorage, clientSource: clientSource, netmapSource: netmapSource, announcedKeys: announcedKeys, contSource: contSource, log: logger.NewLoggerWrapper(zap.L()), } 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 var ecErr *objectSDK.ECInfoError switch { case errors.As(err, &splitErr): return stream.Send(splitInfoResponse(splitErr.SplitInfo())) case errors.As(err, &ecErr): return stream.Send(ecInfoResponse(ecErr.ECInfo())) 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 var ecErr *objectSDK.ECInfoError switch { case errors.As(err, &splitErr): return stream.Send(splitInfoRangeResponse(splitErr.SplitInfo())) case errors.As(err, &ecErr): return stream.Send(ecInfoRangeResponse(ecErr.ECInfo())) 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 var ecErr *objectSDK.ECInfoError if errors.As(err, &splitErr) { setSplitInfoHeadResponse(splitErr.SplitInfo(), resp) err = nil } if errors.As(err, &ecErr) { setECInfoHeadResponse(ecErr.ECInfo(), resp) err = nil } return resp, err } func WithLogger(l *logger.Logger) Option { return func(c *cfg) { c.log = l.With(zap.String("component", "Object.Get V2 service")) } }