package implementations import ( "context" "github.com/multiformats/go-multiaddr" "github.com/nspcc-dev/neofs-api-go/hash" "github.com/nspcc-dev/neofs-api-go/object" "github.com/nspcc-dev/neofs-api-go/refs" "github.com/nspcc-dev/neofs-api-go/service" "github.com/nspcc-dev/neofs-api-go/storagegroup" "github.com/nspcc-dev/neofs-node/internal" "github.com/pkg/errors" "go.uber.org/zap" ) type ( // StorageGroupInfoReceiverParams groups the parameters of // storage group information receiver. StorageGroupInfoReceiverParams struct { SelectiveContainerExecutor SelectiveContainerExecutor Logger *zap.Logger } sgInfoRecv struct { executor SelectiveContainerExecutor log *zap.Logger } ) const locationFinderInstanceFailMsg = "could not create object location finder" // ErrIncompleteSGInfo is returned by storage group information receiver // that could not receive full information. const ErrIncompleteSGInfo = internal.Error("could not receive full storage group info") // PublicSessionToken is a context key for SessionToken. // FIXME: temp solution for cycle import fix. // Unify with same const from transformer pkg. const PublicSessionToken = "public token" // BearerToken is a context key for BearerToken. const BearerToken = "bearer token" // ExtendedHeaders is a context key for X-headers. const ExtendedHeaders = "extended headers" func (s *sgInfoRecv) GetSGInfo(ctx context.Context, cid CID, group []ObjectID) (*storagegroup.StorageGroup, error) { var ( err error res = new(storagegroup.StorageGroup) hashList = make([]hash.Hash, 0, len(group)) ) m := make(map[string]struct{}, len(group)) for i := range group { m[group[i].String()] = struct{}{} } // FIXME: hardcoded for simplicity. // Function is called in next cases: // - SG transformation on trusted node side (only in this case session token is needed); // - SG info check on container nodes (token is not needed since system group has extra access); // - data audit on inner ring nodes (same as previous). var token service.SessionToken if v, ok := ctx.Value(PublicSessionToken).(service.SessionToken); ok { token = v } var bearer service.BearerToken if v, ok := ctx.Value(BearerToken).(service.BearerToken); ok { bearer = v } var extHdrs []service.ExtendedHeader if v, ok := ctx.Value(ExtendedHeaders).([]service.ExtendedHeader); ok { extHdrs = v } if err = s.executor.Head(ctx, &HeadParams{ GetParams: GetParams{ SelectiveParams: SelectiveParams{ CID: cid, TTL: service.SingleForwardingTTL, IDList: group, Breaker: func(addr refs.Address) (cFlag ProgressControlFlag) { if len(m) == 0 { cFlag = BreakProgress } else if _, ok := m[addr.ObjectID.String()]; !ok { cFlag = NextAddress } return }, Token: token, Bearer: bearer, ExtendedHeaders: extHdrs, }, Handler: func(_ multiaddr.Multiaddr, obj *object.Object) { _, hashHeader := obj.LastHeader(object.HeaderType(object.HomoHashHdr)) if hashHeader == nil { return } hashList = append(hashList, hashHeader.Value.(*object.Header_HomoHash).HomoHash) res.ValidationDataSize += obj.SystemHeader.PayloadLength delete(m, obj.SystemHeader.ID.String()) }, }, FullHeaders: true, }); err != nil { return nil, err } else if len(m) > 0 { return nil, ErrIncompleteSGInfo } res.ValidationHash, err = hash.Concat(hashList) return res, err } // NewStorageGroupInfoReceiver constructs storagegroup.InfoReceiver from SelectiveContainerExecutor. func NewStorageGroupInfoReceiver(p StorageGroupInfoReceiverParams) (storagegroup.InfoReceiver, error) { switch { case p.Logger == nil: return nil, errors.Wrap(errEmptyLogger, locationFinderInstanceFailMsg) case p.SelectiveContainerExecutor == nil: return nil, errors.Wrap(errEmptyObjectsContainerHandler, locationFinderInstanceFailMsg) } return &sgInfoRecv{ executor: p.SelectiveContainerExecutor, log: p.Logger, }, nil }