[#236] api: Create info.go for basic structs

Moved BucketInfo and ObjectInfo from layer and handler to api

Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
This commit is contained in:
Angira Kekteeva 2021-08-28 00:33:50 +03:00 committed by Alex Vanin
parent 345dafb29d
commit 239742f413
17 changed files with 231 additions and 229 deletions

34
api/cache/buckets.go vendored
View file

@ -4,27 +4,17 @@ import (
"time" "time"
"github.com/bluele/gcache" "github.com/bluele/gcache"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
) )
type ( type (
// BucketCache provides interface for lru cache for objects. // BucketCache provides interface for lru cache for objects.
BucketCache interface { BucketCache interface {
Get(key string) *BucketInfo Get(key string) *api.BucketInfo
Put(bkt *BucketInfo) error Put(bkt *api.BucketInfo) error
Delete(key string) bool Delete(key string) bool
} }
// BucketInfo stores basic bucket data.
BucketInfo struct {
Name string
CID *cid.ID
Owner *owner.ID
Created time.Time
BasicACL uint32
}
// GetBucketCache contains cache with objects and lifetime of cache entries. // GetBucketCache contains cache with objects and lifetime of cache entries.
GetBucketCache struct { GetBucketCache struct {
cache gcache.Cache cache gcache.Cache
@ -40,13 +30,13 @@ func NewBucketCache(cacheSize int, lifetime time.Duration) *GetBucketCache {
} }
// Get returns cached object. // Get returns cached object.
func (o *GetBucketCache) Get(key string) *BucketInfo { func (o *GetBucketCache) Get(key string) *api.BucketInfo {
entry, err := o.cache.Get(key) entry, err := o.cache.Get(key)
if err != nil { if err != nil {
return nil return nil
} }
result, ok := entry.(*BucketInfo) result, ok := entry.(*api.BucketInfo)
if !ok { if !ok {
return nil return nil
} }
@ -55,7 +45,7 @@ func (o *GetBucketCache) Get(key string) *BucketInfo {
} }
// Put puts an object to cache. // Put puts an object to cache.
func (o *GetBucketCache) Put(bkt *BucketInfo) error { func (o *GetBucketCache) Put(bkt *api.BucketInfo) error {
return o.cache.SetWithExpire(bkt.Name, bkt, o.lifetime) return o.cache.SetWithExpire(bkt.Name, bkt, o.lifetime)
} }
@ -63,15 +53,3 @@ func (o *GetBucketCache) Put(bkt *BucketInfo) error {
func (o *GetBucketCache) Delete(key string) bool { func (o *GetBucketCache) Delete(key string) bool {
return o.cache.Remove(key) return o.cache.Remove(key)
} }
const bktVersionSettingsObject = ".s3-versioning-settings"
// SettingsObjectName is system name for bucket settings file.
func (b *BucketInfo) SettingsObjectName() string {
return bktVersionSettingsObject
}
// SystemObjectKey is key to use in SystemCache.
func (b *BucketInfo) SystemObjectKey(obj string) string {
return b.Name + obj
}

View file

@ -14,7 +14,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/v2/acl" "github.com/nspcc-dev/neofs-api-go/v2/acl"
"github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
"github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/errors"
"github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-s3-gw/api/layer"
) )
@ -300,7 +299,7 @@ func (h *handler) GetBucketPolicyHandler(w http.ResponseWriter, r *http.Request)
} }
} }
func checkOwner(info *cache.BucketInfo, owner string) error { func checkOwner(info *api.BucketInfo, owner string) error {
if owner == "" { if owner == "" {
return nil return nil
} }

View file

@ -32,7 +32,7 @@ func path2BucketObject(path string) (bucket, prefix string) {
func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) { func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
var ( var (
err error err error
info *layer.ObjectInfo info *api.ObjectInfo
metadata map[string]string metadata map[string]string
reqInfo = api.GetReqInfo(r.Context()) reqInfo = api.GetReqInfo(r.Context())
@ -118,7 +118,7 @@ func (h *handler) CopyObjectHandler(w http.ResponseWriter, r *http.Request) {
h.log.Info("object is copied", h.log.Info("object is copied",
zap.String("bucket", info.Bucket), zap.String("bucket", info.Bucket),
zap.String("object", info.Name), zap.String("object", info.Name),
zap.Stringer("object_id", info.ID())) zap.Stringer("object_id", info.ID))
} }
func parseCopyObjectArgs(headers http.Header) (*copyObjectArgs, error) { func parseCopyObjectArgs(headers http.Header) (*copyObjectArgs, error) {

View file

@ -65,14 +65,14 @@ func fetchRangeHeader(headers http.Header, fullSize uint64) (*layer.RangeParams,
return &layer.RangeParams{Start: start, End: end}, nil return &layer.RangeParams{Start: start, End: end}, nil
} }
func writeHeaders(h http.Header, info *layer.ObjectInfo, tagSetLength int) { func writeHeaders(h http.Header, info *api.ObjectInfo, tagSetLength int) {
if len(info.ContentType) > 0 { if len(info.ContentType) > 0 {
h.Set(api.ContentType, info.ContentType) h.Set(api.ContentType, info.ContentType)
} }
h.Set(api.LastModified, info.Created.UTC().Format(http.TimeFormat)) h.Set(api.LastModified, info.Created.UTC().Format(http.TimeFormat))
h.Set(api.ContentLength, strconv.FormatInt(info.Size, 10)) h.Set(api.ContentLength, strconv.FormatInt(info.Size, 10))
h.Set(api.ETag, info.HashSum) h.Set(api.ETag, info.HashSum)
h.Set(api.AmzVersionID, info.ID().String()) h.Set(api.AmzVersionID, info.ID.String())
h.Set(api.AmzTaggingCount, strconv.Itoa(tagSetLength)) h.Set(api.AmzTaggingCount, strconv.Itoa(tagSetLength))
for key, val := range info.Headers { for key, val := range info.Headers {
@ -83,7 +83,7 @@ func writeHeaders(h http.Header, info *layer.ObjectInfo, tagSetLength int) {
func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) { func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
var ( var (
err error err error
info *layer.ObjectInfo info *api.ObjectInfo
params *layer.RangeParams params *layer.RangeParams
reqInfo = api.GetReqInfo(r.Context()) reqInfo = api.GetReqInfo(r.Context())
@ -143,7 +143,7 @@ func (h *handler) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
func checkPreconditions(info *layer.ObjectInfo, args *conditionalArgs) error { func checkPreconditions(info *api.ObjectInfo, args *conditionalArgs) error {
if len(args.IfMatch) > 0 && args.IfMatch != info.HashSum { if len(args.IfMatch) > 0 && args.IfMatch != info.HashSum {
return errors.GetAPIError(errors.ErrPreconditionFailed) return errors.GetAPIError(errors.ErrPreconditionFailed)
} }

View file

@ -5,6 +5,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/errors"
"github.com/nspcc-dev/neofs-s3-gw/api/layer" "github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -45,8 +46,8 @@ func TestFetchRangeHeader(t *testing.T) {
} }
} }
func newInfo(etag string, created time.Time) *layer.ObjectInfo { func newInfo(etag string, created time.Time) *api.ObjectInfo {
return &layer.ObjectInfo{ return &api.ObjectInfo{
HashSum: etag, HashSum: etag,
Created: created, Created: created,
} }
@ -60,13 +61,13 @@ func TestPreconditions(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
name string name string
info *layer.ObjectInfo info *api.ObjectInfo
args *conditionalArgs args *conditionalArgs
expected error expected error
}{ }{
{ {
name: "no conditions", name: "no conditions",
info: new(layer.ObjectInfo), info: new(api.ObjectInfo),
args: new(conditionalArgs), args: new(conditionalArgs),
expected: nil, expected: nil,
}, },

View file

@ -27,7 +27,7 @@ func getRangeToDetectContentType(maxSize int64) *layer.RangeParams {
func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) { func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
var ( var (
err error err error
info *layer.ObjectInfo info *api.ObjectInfo
reqInfo = api.GetReqInfo(r.Context()) reqInfo = api.GetReqInfo(r.Context())
) )
@ -62,7 +62,7 @@ func (h *handler) HeadObjectHandler(w http.ResponseWriter, r *http.Request) {
VersionID: reqInfo.URL.Query().Get(api.QueryVersionID), VersionID: reqInfo.URL.Query().Get(api.QueryVersionID),
} }
if err = h.obj.GetObject(r.Context(), getParams); err != nil { if err = h.obj.GetObject(r.Context(), getParams); err != nil {
h.logAndSendError(w, "could not get object", reqInfo, err, zap.Stringer("oid", info.ID())) h.logAndSendError(w, "could not get object", reqInfo, err, zap.Stringer("oid", info.ID))
return return
} }
info.ContentType = http.DetectContentType(buffer.Bytes()) info.ContentType = http.DetectContentType(buffer.Bytes())

View file

@ -183,11 +183,11 @@ func fillPrefixes(src []string, encode string) []CommonPrefix {
return dst return dst
} }
func fillContentsWithOwner(src []*layer.ObjectInfo, encode string) []Object { func fillContentsWithOwner(src []*api.ObjectInfo, encode string) []Object {
return fillContents(src, encode, true) return fillContents(src, encode, true)
} }
func fillContents(src []*layer.ObjectInfo, encode string, fetchOwner bool) []Object { func fillContents(src []*api.ObjectInfo, encode string, fetchOwner bool) []Object {
var dst []Object var dst []Object
for _, obj := range src { for _, obj := range src {
res := Object{ res := Object{

65
api/info.go Normal file
View file

@ -0,0 +1,65 @@
package api
import (
"time"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
"github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
)
const bktVersionSettingsObject = ".s3-versioning-settings"
type (
// BucketInfo stores basic bucket data.
BucketInfo struct {
Name string
CID *cid.ID
Owner *owner.ID
Created time.Time
BasicACL uint32
}
// ObjectInfo holds S3 object data.
ObjectInfo struct {
ID *object.ID
CID *cid.ID
IsDir bool
Bucket string
Name string
Size int64
ContentType string
Created time.Time
CreationEpoch uint64
HashSum string
Owner *owner.ID
Headers map[string]string
}
)
// SettingsObjectName is system name for bucket settings file.
func (b *BucketInfo) SettingsObjectName() string { return bktVersionSettingsObject }
// SystemObjectKey is key to use in SystemCache.
func (b *BucketInfo) SystemObjectKey(obj string) string {
return b.Name + obj
}
// Version returns object version from ObjectInfo.
func (o *ObjectInfo) Version() string { return o.ID.String() }
// NiceName returns object name for cache.
func (o *ObjectInfo) NiceName() string { return o.Bucket + "/" + o.Name }
// Address returns object address.
func (o *ObjectInfo) Address() *object.Address {
address := object.NewAddress()
address.SetContainerID(o.CID)
address.SetObjectID(o.ID)
return address
}
// TagsObject returns name of system object for tags.
func (o *ObjectInfo) TagsObject() string { return ".tagset." + o.Name + "." + o.Version() }

View file

@ -12,7 +12,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/container" "github.com/nspcc-dev/neofs-api-go/pkg/container"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
"github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
"github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/errors"
"github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/pool"
"go.uber.org/zap" "go.uber.org/zap"
@ -21,19 +20,19 @@ import (
type ( type (
// BucketACL extends BucketInfo by eacl.Table. // BucketACL extends BucketInfo by eacl.Table.
BucketACL struct { BucketACL struct {
Info *cache.BucketInfo Info *api.BucketInfo
EACL *eacl.Table EACL *eacl.Table
} }
) )
func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*cache.BucketInfo, error) { func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*api.BucketInfo, error) {
var ( var (
err error err error
res *container.Container res *container.Container
rid = api.GetRequestID(ctx) rid = api.GetRequestID(ctx)
bearerOpt = n.BearerOpt(ctx) bearerOpt = n.BearerOpt(ctx)
info = &cache.BucketInfo{ info = &api.BucketInfo{
CID: cid, CID: cid,
Name: cid.String(), Name: cid.String(),
} }
@ -84,7 +83,7 @@ func (n *layer) containerInfo(ctx context.Context, cid *cid.ID) (*cache.BucketIn
return info, nil return info, nil
} }
func (n *layer) containerList(ctx context.Context) ([]*cache.BucketInfo, error) { func (n *layer) containerList(ctx context.Context) ([]*api.BucketInfo, error) {
var ( var (
err error err error
own = n.Owner(ctx) own = n.Owner(ctx)
@ -100,7 +99,7 @@ func (n *layer) containerList(ctx context.Context) ([]*cache.BucketInfo, error)
return nil, err return nil, err
} }
list := make([]*cache.BucketInfo, 0, len(res)) list := make([]*api.BucketInfo, 0, len(res))
for _, cid := range res { for _, cid := range res {
info, err := n.containerInfo(ctx, cid) info, err := n.containerInfo(ctx, cid)
if err != nil { if err != nil {
@ -118,7 +117,7 @@ func (n *layer) containerList(ctx context.Context) ([]*cache.BucketInfo, error)
func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) { func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) {
var err error var err error
bktInfo := &cache.BucketInfo{ bktInfo := &api.BucketInfo{
Name: p.Name, Name: p.Name,
Owner: n.Owner(ctx), Owner: n.Owner(ctx),
Created: time.Now(), Created: time.Now(),

View file

@ -54,7 +54,7 @@ type (
// GetObjectParams stores object get request parameters. // GetObjectParams stores object get request parameters.
GetObjectParams struct { GetObjectParams struct {
Range *RangeParams Range *RangeParams
ObjectInfo *ObjectInfo ObjectInfo *api.ObjectInfo
Offset int64 Offset int64
Length int64 Length int64
Writer io.Writer Writer io.Writer
@ -96,7 +96,7 @@ type (
// CopyObjectParams stores object copy request parameters. // CopyObjectParams stores object copy request parameters.
CopyObjectParams struct { CopyObjectParams struct {
SrcObject *ObjectInfo SrcObject *api.ObjectInfo
DstBucket string DstBucket string
DstObject string DstObject string
SrcSize int64 SrcSize int64
@ -138,7 +138,7 @@ type (
// PutTaggingParams stores tag set params. // PutTaggingParams stores tag set params.
PutTaggingParams struct { PutTaggingParams struct {
ObjectInfo *ObjectInfo ObjectInfo *api.ObjectInfo
TagSet map[string]string TagSet map[string]string
} }
@ -151,33 +151,33 @@ type (
Client interface { Client interface {
NeoFS NeoFS
PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*ObjectInfo, error) PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*api.ObjectInfo, error)
GetBucketVersioning(ctx context.Context, name string) (*BucketSettings, error) GetBucketVersioning(ctx context.Context, name string) (*BucketSettings, error)
ListBuckets(ctx context.Context) ([]*cache.BucketInfo, error) ListBuckets(ctx context.Context) ([]*api.BucketInfo, error)
GetBucketInfo(ctx context.Context, name string) (*cache.BucketInfo, error) GetBucketInfo(ctx context.Context, name string) (*api.BucketInfo, error)
GetBucketACL(ctx context.Context, name string) (*BucketACL, error) GetBucketACL(ctx context.Context, name string) (*BucketACL, error)
PutBucketACL(ctx context.Context, p *PutBucketACLParams) error PutBucketACL(ctx context.Context, p *PutBucketACLParams) error
CreateBucket(ctx context.Context, p *CreateBucketParams) (*cid.ID, error) CreateBucket(ctx context.Context, p *CreateBucketParams) (*cid.ID, error)
DeleteBucket(ctx context.Context, p *DeleteBucketParams) error DeleteBucket(ctx context.Context, p *DeleteBucketParams) error
GetObject(ctx context.Context, p *GetObjectParams) error GetObject(ctx context.Context, p *GetObjectParams) error
GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*ObjectInfo, error) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*api.ObjectInfo, error)
GetObjectTagging(ctx context.Context, p *ObjectInfo) (map[string]string, error) GetObjectTagging(ctx context.Context, p *api.ObjectInfo) (map[string]string, error)
GetBucketTagging(ctx context.Context, bucket string) (map[string]string, error) GetBucketTagging(ctx context.Context, bucket string) (map[string]string, error)
PutObject(ctx context.Context, p *PutObjectParams) (*ObjectInfo, error) PutObject(ctx context.Context, p *PutObjectParams) (*api.ObjectInfo, error)
PutObjectTagging(ctx context.Context, p *PutTaggingParams) error PutObjectTagging(ctx context.Context, p *PutTaggingParams) error
PutBucketTagging(ctx context.Context, bucket string, tagSet map[string]string) error PutBucketTagging(ctx context.Context, bucket string, tagSet map[string]string) error
CopyObject(ctx context.Context, p *CopyObjectParams) (*ObjectInfo, error) CopyObject(ctx context.Context, p *CopyObjectParams) (*api.ObjectInfo, error)
ListObjectsV1(ctx context.Context, p *ListObjectsParamsV1) (*ListObjectsInfoV1, error) ListObjectsV1(ctx context.Context, p *ListObjectsParamsV1) (*ListObjectsInfoV1, error)
ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*ListObjectsInfoV2, error) ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*ListObjectsInfoV2, error)
ListObjectVersions(ctx context.Context, p *ListObjectVersionsParams) (*ListObjectVersionsInfo, error) ListObjectVersions(ctx context.Context, p *ListObjectVersionsParams) (*ListObjectVersionsInfo, error)
DeleteObjects(ctx context.Context, bucket string, objects []*VersionedObject) []error DeleteObjects(ctx context.Context, bucket string, objects []*VersionedObject) []error
DeleteObjectTagging(ctx context.Context, p *ObjectInfo) error DeleteObjectTagging(ctx context.Context, p *api.ObjectInfo) error
DeleteBucketTagging(ctx context.Context, bucket string) error DeleteBucketTagging(ctx context.Context, bucket string) error
} }
) )
@ -240,7 +240,7 @@ func (n *layer) Get(ctx context.Context, address *object.Address) (*object.Objec
} }
// GetBucketInfo returns bucket info by name. // GetBucketInfo returns bucket info by name.
func (n *layer) GetBucketInfo(ctx context.Context, name string) (*cache.BucketInfo, error) { func (n *layer) GetBucketInfo(ctx context.Context, name string) (*api.BucketInfo, error) {
name, err := url.QueryUnescape(name) name, err := url.QueryUnescape(name)
if err != nil { if err != nil {
return nil, err return nil, err
@ -298,7 +298,7 @@ func (n *layer) PutBucketACL(ctx context.Context, param *PutBucketACLParams) err
// ListBuckets returns all user containers. Name of the bucket is a container // ListBuckets returns all user containers. Name of the bucket is a container
// id. Timestamp is omitted since it is not saved in neofs container. // id. Timestamp is omitted since it is not saved in neofs container.
func (n *layer) ListBuckets(ctx context.Context) ([]*cache.BucketInfo, error) { func (n *layer) ListBuckets(ctx context.Context) ([]*api.BucketInfo, error) {
return n.containerList(ctx) return n.containerList(ctx)
} }
@ -308,8 +308,8 @@ func (n *layer) GetObject(ctx context.Context, p *GetObjectParams) error {
params := &getParams{ params := &getParams{
Writer: p.Writer, Writer: p.Writer,
cid: p.ObjectInfo.CID(), cid: p.ObjectInfo.CID,
oid: p.ObjectInfo.ID(), oid: p.ObjectInfo.ID,
offset: p.Offset, offset: p.Offset,
length: p.Length, length: p.Length,
} }
@ -327,14 +327,14 @@ func (n *layer) GetObject(ctx context.Context, p *GetObjectParams) error {
if err != nil { if err != nil {
n.objCache.Delete(p.ObjectInfo.Address()) n.objCache.Delete(p.ObjectInfo.Address())
return fmt.Errorf("couldn't get object, cid: %s : %w", p.ObjectInfo.CID(), err) return fmt.Errorf("couldn't get object, cid: %s : %w", p.ObjectInfo.CID, err)
} }
return nil return nil
} }
// GetObjectInfo returns meta information about the object. // GetObjectInfo returns meta information about the object.
func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*ObjectInfo, error) { func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*api.ObjectInfo, error) {
bkt, err := n.GetBucketInfo(ctx, p.Bucket) bkt, err := n.GetBucketInfo(ctx, p.Bucket)
if err != nil { if err != nil {
n.log.Error("could not fetch bucket info", zap.Error(err)) n.log.Error("could not fetch bucket info", zap.Error(err))
@ -349,7 +349,7 @@ func (n *layer) GetObjectInfo(ctx context.Context, p *HeadObjectParams) (*Object
} }
// PutObject into storage. // PutObject into storage.
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*ObjectInfo, error) { func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*api.ObjectInfo, error) {
bkt, err := n.GetBucketInfo(ctx, p.Bucket) bkt, err := n.GetBucketInfo(ctx, p.Bucket)
if err != nil { if err != nil {
return nil, err return nil, err
@ -359,10 +359,10 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*ObjectInfo,
} }
// GetObjectTagging from storage. // GetObjectTagging from storage.
func (n *layer) GetObjectTagging(ctx context.Context, oi *ObjectInfo) (map[string]string, error) { func (n *layer) GetObjectTagging(ctx context.Context, oi *api.ObjectInfo) (map[string]string, error) {
bktInfo := &cache.BucketInfo{ bktInfo := &api.BucketInfo{
Name: oi.Bucket, Name: oi.Bucket,
CID: oi.CID(), CID: oi.CID,
Owner: oi.Owner, Owner: oi.Owner,
} }
@ -389,7 +389,7 @@ func (n *layer) GetBucketTagging(ctx context.Context, bucketName string) (map[st
return formTagSet(objInfo), nil return formTagSet(objInfo), nil
} }
func formTagSet(objInfo *ObjectInfo) map[string]string { func formTagSet(objInfo *api.ObjectInfo) map[string]string {
var tagSet map[string]string var tagSet map[string]string
if objInfo != nil { if objInfo != nil {
tagSet = make(map[string]string, len(objInfo.Headers)) tagSet = make(map[string]string, len(objInfo.Headers))
@ -407,9 +407,9 @@ func formTagSet(objInfo *ObjectInfo) map[string]string {
// PutObjectTagging into storage. // PutObjectTagging into storage.
func (n *layer) PutObjectTagging(ctx context.Context, p *PutTaggingParams) error { func (n *layer) PutObjectTagging(ctx context.Context, p *PutTaggingParams) error {
bktInfo := &cache.BucketInfo{ bktInfo := &api.BucketInfo{
Name: p.ObjectInfo.Bucket, Name: p.ObjectInfo.Bucket,
CID: p.ObjectInfo.CID(), CID: p.ObjectInfo.CID,
Owner: p.ObjectInfo.Owner, Owner: p.ObjectInfo.Owner,
} }
@ -435,7 +435,7 @@ func (n *layer) PutBucketTagging(ctx context.Context, bucketName string, tagSet
} }
// DeleteObjectTagging from storage. // DeleteObjectTagging from storage.
func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectInfo) error { func (n *layer) DeleteObjectTagging(ctx context.Context, p *api.ObjectInfo) error {
bktInfo, err := n.GetBucketInfo(ctx, p.Bucket) bktInfo, err := n.GetBucketInfo(ctx, p.Bucket)
if err != nil { if err != nil {
return err return err
@ -443,7 +443,7 @@ func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectInfo) error {
return n.deleteSystemObject(ctx, bktInfo, p.TagsObject()) return n.deleteSystemObject(ctx, bktInfo, p.TagsObject())
} }
func (n *layer) deleteSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, name string) error { func (n *layer) deleteSystemObject(ctx context.Context, bktInfo *api.BucketInfo, name string) error {
var oid *object.ID var oid *object.ID
if meta := n.systemCache.Get(bktInfo.SystemObjectKey(name)); meta != nil { if meta := n.systemCache.Get(bktInfo.SystemObjectKey(name)); meta != nil {
oid = meta.ID() oid = meta.ID()
@ -472,7 +472,7 @@ func (n *layer) DeleteBucketTagging(ctx context.Context, bucketName string) erro
return n.deleteSystemObject(ctx, bktInfo, formBucketTagObjectName(bucketName)) return n.deleteSystemObject(ctx, bktInfo, formBucketTagObjectName(bucketName))
} }
func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo, objName string, metadata map[string]string, prefix string) (*object.Object, error) { func (n *layer) putSystemObject(ctx context.Context, bktInfo *api.BucketInfo, objName string, metadata map[string]string, prefix string) (*object.Object, error) {
var ( var (
err error err error
oldOID *object.ID oldOID *object.ID
@ -539,7 +539,7 @@ func (n *layer) putSystemObject(ctx context.Context, bktInfo *cache.BucketInfo,
return meta, nil return meta, nil
} }
func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objName string) (*ObjectInfo, error) { func (n *layer) getSystemObject(ctx context.Context, bkt *api.BucketInfo, objName string) (*api.ObjectInfo, error) {
if meta := n.systemCache.Get(bkt.SystemObjectKey(objName)); meta != nil { if meta := n.systemCache.Get(bkt.SystemObjectKey(objName)); meta != nil {
return objInfoFromMeta(bkt, meta), nil return objInfoFromMeta(bkt, meta), nil
} }
@ -561,7 +561,7 @@ func (n *layer) getSystemObject(ctx context.Context, bkt *cache.BucketInfo, objN
} }
// CopyObject from one bucket into another bucket. // CopyObject from one bucket into another bucket.
func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*ObjectInfo, error) { func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*api.ObjectInfo, error) {
pr, pw := io.Pipe() pr, pw := io.Pipe()
go func() { go func() {
@ -585,7 +585,7 @@ func (n *layer) CopyObject(ctx context.Context, p *CopyObjectParams) (*ObjectInf
} }
// DeleteObject removes all objects with passed nice name. // DeleteObject removes all objects with passed nice name.
func (n *layer) deleteObject(ctx context.Context, bkt *cache.BucketInfo, obj *VersionedObject) error { func (n *layer) deleteObject(ctx context.Context, bkt *api.BucketInfo, obj *VersionedObject) error {
var ( var (
err error err error
ids []*object.ID ids []*object.ID
@ -627,7 +627,7 @@ func (n *layer) deleteObject(ctx context.Context, bkt *cache.BucketInfo, obj *Ve
if err = n.objectDelete(ctx, bkt.CID, id); err != nil { if err = n.objectDelete(ctx, bkt.CID, id); err != nil {
return err return err
} }
if err = n.DeleteObjectTagging(ctx, &ObjectInfo{id: id, Bucket: bkt.Name, Name: obj.Name}); err != nil { if err = n.DeleteObjectTagging(ctx, &api.ObjectInfo{ID: id, Bucket: bkt.Name, Name: obj.Name}); err != nil {
return err return err
} }
} }

View file

@ -15,7 +15,6 @@ import (
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/pkg/owner" "github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
apiErrors "github.com/nspcc-dev/neofs-s3-gw/api/errors" apiErrors "github.com/nspcc-dev/neofs-s3-gw/api/errors"
"go.uber.org/zap" "go.uber.org/zap"
) )
@ -61,7 +60,7 @@ type (
} }
allObjectParams struct { allObjectParams struct {
Bucket *cache.BucketInfo Bucket *api.BucketInfo
Delimiter string Delimiter string
Prefix string Prefix string
} }
@ -128,7 +127,7 @@ func (n *layer) objectRange(ctx context.Context, p *getParams) ([]byte, error) {
} }
// objectPut into NeoFS, took payload from io.Reader. // objectPut into NeoFS, took payload from io.Reader.
func (n *layer) objectPut(ctx context.Context, bkt *cache.BucketInfo, p *PutObjectParams) (*ObjectInfo, error) { func (n *layer) objectPut(ctx context.Context, bkt *api.BucketInfo, p *PutObjectParams) (*api.ObjectInfo, error) {
own := n.Owner(ctx) own := n.Owner(ctx)
obj, err := url.QueryUnescape(p.Object) obj, err := url.QueryUnescape(p.Object)
if err != nil { if err != nil {
@ -190,9 +189,9 @@ func (n *layer) objectPut(ctx context.Context, bkt *cache.BucketInfo, p *PutObje
} }
} }
return &ObjectInfo{ return &api.ObjectInfo{
id: oid, ID: oid,
bucketID: bkt.CID, CID: bkt.CID,
Owner: own, Owner: own,
Bucket: p.Bucket, Bucket: p.Bucket,
@ -264,14 +263,14 @@ func updateCRDT2PSetHeaders(p *PutObjectParams, versions *objectVersions, versio
if lastVersion := versions.getLast(); lastVersion != nil { if lastVersion := versions.getLast(); lastVersion != nil {
p.Header[versionsDelAttr] = versionsDeletedStr + lastVersion.Version() p.Header[versionsDelAttr] = versionsDeletedStr + lastVersion.Version()
idsToDeleteArr = append(idsToDeleteArr, lastVersion.ID()) idsToDeleteArr = append(idsToDeleteArr, lastVersion.ID)
} else if len(versionsDeletedStr) != 0 { } else if len(versionsDeletedStr) != 0 {
p.Header[versionsDelAttr] = versionsDeletedStr p.Header[versionsDelAttr] = versionsDeletedStr
} }
for _, version := range versions.objects { for _, version := range versions.objects {
if contains(versions.delList, version.Version()) { if contains(versions.delList, version.Version()) {
idsToDeleteArr = append(idsToDeleteArr, version.ID()) idsToDeleteArr = append(idsToDeleteArr, version.ID)
} }
} }
} }
@ -279,7 +278,7 @@ func updateCRDT2PSetHeaders(p *PutObjectParams, versions *objectVersions, versio
return idsToDeleteArr return idsToDeleteArr
} }
func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *cache.BucketInfo, objectName string) (*ObjectInfo, error) { func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *api.BucketInfo, objectName string) (*api.ObjectInfo, error) {
if address := n.namesCache.Get(bkt.Name + "/" + objectName); address != nil { if address := n.namesCache.Get(bkt.Name + "/" + objectName); address != nil {
if headInfo := n.objCache.Get(address); headInfo != nil { if headInfo := n.objCache.Get(address); headInfo != nil {
return objInfoFromMeta(bkt, headInfo), nil return objInfoFromMeta(bkt, headInfo), nil
@ -305,7 +304,7 @@ func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *cache.Buck
return lastVersion, nil return lastVersion, nil
} }
func (n *layer) headVersions(ctx context.Context, bkt *cache.BucketInfo, objectName string) (*objectVersions, error) { func (n *layer) headVersions(ctx context.Context, bkt *api.BucketInfo, objectName string) (*objectVersions, error) {
ids, err := n.objectSearch(ctx, &findParams{cid: bkt.CID, val: objectName}) ids, err := n.objectSearch(ctx, &findParams{cid: bkt.CID, val: objectName})
if err != nil { if err != nil {
return nil, err return nil, err
@ -343,7 +342,7 @@ func (n *layer) headVersions(ctx context.Context, bkt *cache.BucketInfo, objectN
return versions, nil return versions, nil
} }
func (n *layer) headVersion(ctx context.Context, bkt *cache.BucketInfo, versionID string) (*ObjectInfo, error) { func (n *layer) headVersion(ctx context.Context, bkt *api.BucketInfo, versionID string) (*api.ObjectInfo, error) {
oid := object.NewID() oid := object.NewID()
if err := oid.Parse(versionID); err != nil { if err := oid.Parse(versionID); err != nil {
return nil, err return nil, err
@ -365,9 +364,9 @@ func (n *layer) headVersion(ctx context.Context, bkt *cache.BucketInfo, versionI
if err = n.objCache.Put(*meta); err != nil { if err = n.objCache.Put(*meta); err != nil {
n.log.Warn("couldn't put obj to object cache", n.log.Warn("couldn't put obj to object cache",
zap.String("bucket name", objInfo.Bucket), zap.String("bucket name", objInfo.Bucket),
zap.Stringer("bucket cid", objInfo.CID()), zap.Stringer("bucket cid", objInfo.CID),
zap.String("object name", objInfo.Name), zap.String("object name", objInfo.Name),
zap.Stringer("object id", objInfo.ID()), zap.Stringer("object id", objInfo.ID),
zap.Error(err)) zap.Error(err))
} }
@ -388,7 +387,7 @@ func (n *layer) ListObjectsV1(ctx context.Context, p *ListObjectsParamsV1) (*Lis
var ( var (
err error err error
result ListObjectsInfoV1 result ListObjectsInfoV1
allObjects []*ObjectInfo allObjects []*api.ObjectInfo
) )
if p.MaxKeys == 0 { if p.MaxKeys == 0 {
@ -423,7 +422,7 @@ func (n *layer) ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*Lis
var ( var (
err error err error
result ListObjectsInfoV2 result ListObjectsInfoV2
allObjects []*ObjectInfo allObjects []*api.ObjectInfo
) )
if p.MaxKeys == 0 { if p.MaxKeys == 0 {
@ -449,7 +448,7 @@ func (n *layer) ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*Lis
if len(allObjects) > p.MaxKeys { if len(allObjects) > p.MaxKeys {
result.IsTruncated = true result.IsTruncated = true
allObjects = allObjects[:p.MaxKeys] allObjects = allObjects[:p.MaxKeys]
result.NextContinuationToken = allObjects[len(allObjects)-1].id.String() result.NextContinuationToken = allObjects[len(allObjects)-1].ID.String()
} }
result.Prefixes, result.Objects = triageObjects(allObjects) result.Prefixes, result.Objects = triageObjects(allObjects)
@ -457,13 +456,13 @@ func (n *layer) ListObjectsV2(ctx context.Context, p *ListObjectsParamsV2) (*Lis
return &result, nil return &result, nil
} }
func (n *layer) listSortedObjectsFromNeoFS(ctx context.Context, p allObjectParams) ([]*ObjectInfo, error) { func (n *layer) listSortedObjectsFromNeoFS(ctx context.Context, p allObjectParams) ([]*api.ObjectInfo, error) {
versions, err := n.getAllObjectsVersions(ctx, p.Bucket, p.Prefix, p.Delimiter) versions, err := n.getAllObjectsVersions(ctx, p.Bucket, p.Prefix, p.Delimiter)
if err != nil { if err != nil {
return nil, err return nil, err
} }
objects := make([]*ObjectInfo, 0, len(versions)) objects := make([]*api.ObjectInfo, 0, len(versions))
for _, v := range versions { for _, v := range versions {
lastVersion := v.getLast() lastVersion := v.getLast()
if lastVersion != nil { if lastVersion != nil {
@ -478,7 +477,7 @@ func (n *layer) listSortedObjectsFromNeoFS(ctx context.Context, p allObjectParam
return objects, nil return objects, nil
} }
func (n *layer) getAllObjectsVersions(ctx context.Context, bkt *cache.BucketInfo, prefix, delimiter string) (map[string]*objectVersions, error) { func (n *layer) getAllObjectsVersions(ctx context.Context, bkt *api.BucketInfo, prefix, delimiter string) (map[string]*objectVersions, error) {
ids, err := n.objectSearch(ctx, &findParams{cid: bkt.CID}) ids, err := n.objectSearch(ctx, &findParams{cid: bkt.CID})
if err != nil { if err != nil {
return nil, err return nil, err
@ -526,12 +525,12 @@ func splitVersions(header string) []string {
return strings.Split(header, ",") return strings.Split(header, ",")
} }
func isSystem(obj *ObjectInfo) bool { func isSystem(obj *api.ObjectInfo) bool {
return len(obj.Headers[objectSystemAttributeName]) > 0 || return len(obj.Headers[objectSystemAttributeName]) > 0 ||
len(obj.Headers[attrVersionsIgnore]) > 0 len(obj.Headers[attrVersionsIgnore]) > 0
} }
func trimAfterObjectName(startAfter string, objects []*ObjectInfo) []*ObjectInfo { func trimAfterObjectName(startAfter string, objects []*api.ObjectInfo) []*api.ObjectInfo {
if len(objects) != 0 && objects[len(objects)-1].Name <= startAfter { if len(objects) != 0 && objects[len(objects)-1].Name <= startAfter {
return nil return nil
} }
@ -544,12 +543,12 @@ func trimAfterObjectName(startAfter string, objects []*ObjectInfo) []*ObjectInfo
return nil return nil
} }
func trimAfterObjectID(id string, objects []*ObjectInfo) []*ObjectInfo { func trimAfterObjectID(id string, objects []*api.ObjectInfo) []*api.ObjectInfo {
if len(objects) != 0 && objects[len(objects)-1].id.String() == id { if len(objects) != 0 && objects[len(objects)-1].ID.String() == id {
return []*ObjectInfo{} return []*api.ObjectInfo{}
} }
for i, obj := range objects { for i, obj := range objects {
if obj.ID().String() == id { if obj.ID.String() == id {
return objects[i+1:] return objects[i+1:]
} }
} }
@ -557,9 +556,9 @@ func trimAfterObjectID(id string, objects []*ObjectInfo) []*ObjectInfo {
return nil return nil
} }
func triageObjects(allObjects []*ObjectInfo) (prefixes []string, objects []*ObjectInfo) { func triageObjects(allObjects []*api.ObjectInfo) (prefixes []string, objects []*api.ObjectInfo) {
for _, ov := range allObjects { for _, ov := range allObjects {
if ov.isDir { if ov.IsDir {
prefixes = append(prefixes, ov.Name) prefixes = append(prefixes, ov.Name)
} else { } else {
objects = append(objects, ov) objects = append(objects, ov)
@ -569,12 +568,12 @@ func triageObjects(allObjects []*ObjectInfo) (prefixes []string, objects []*Obje
return return
} }
func (n *layer) listAllObjects(ctx context.Context, p ListObjectsParamsCommon) ([]*ObjectInfo, error) { func (n *layer) listAllObjects(ctx context.Context, p ListObjectsParamsCommon) ([]*api.ObjectInfo, error) {
var ( var (
err error err error
bkt *cache.BucketInfo bkt *api.BucketInfo
cacheKey cacheOptions cacheKey cacheOptions
allObjects []*ObjectInfo allObjects []*api.ObjectInfo
) )
if bkt, err = n.GetBucketInfo(ctx, p.Bucket); err != nil { if bkt, err = n.GetBucketInfo(ctx, p.Bucket); err != nil {
@ -598,13 +597,13 @@ func (n *layer) listAllObjects(ctx context.Context, p ListObjectsParamsCommon) (
} }
// putting to cache a copy of allObjects because allObjects can be modified further // putting to cache a copy of allObjects because allObjects can be modified further
n.listsCache.Put(cacheKey, append([]*ObjectInfo(nil), allObjects...)) n.listsCache.Put(cacheKey, append([]*api.ObjectInfo(nil), allObjects...))
} }
return allObjects, nil return allObjects, nil
} }
func (n *layer) isVersioningEnabled(ctx context.Context, bktInfo *cache.BucketInfo) bool { func (n *layer) isVersioningEnabled(ctx context.Context, bktInfo *api.BucketInfo) bool {
settings, err := n.getBucketSettings(ctx, bktInfo) settings, err := n.getBucketSettings(ctx, bktInfo)
if err != nil { if err != nil {
n.log.Warn("couldn't get versioning settings object", zap.Error(err)) n.log.Warn("couldn't get versioning settings object", zap.Error(err))

View file

@ -5,6 +5,7 @@ import (
"time" "time"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
"github.com/nspcc-dev/neofs-s3-gw/api"
) )
/* /*
@ -21,8 +22,8 @@ import (
// ObjectsListCache provides interface for cache of ListObjectsV2 in a layer struct. // ObjectsListCache provides interface for cache of ListObjectsV2 in a layer struct.
type ( type (
ObjectsListCache interface { ObjectsListCache interface {
Get(key cacheOptions) []*ObjectInfo Get(key cacheOptions) []*api.ObjectInfo
Put(key cacheOptions, objects []*ObjectInfo) Put(key cacheOptions, objects []*api.ObjectInfo)
} }
) )
@ -41,7 +42,7 @@ type (
mtx sync.RWMutex mtx sync.RWMutex
} }
cacheEntry struct { cacheEntry struct {
list []*ObjectInfo list []*api.ObjectInfo
} }
cacheOptions struct { cacheOptions struct {
method string method string
@ -58,7 +59,7 @@ func newListObjectsCache(lifetime time.Duration) *listObjectsCache {
} }
} }
func (l *listObjectsCache) Get(key cacheOptions) []*ObjectInfo { func (l *listObjectsCache) Get(key cacheOptions) []*api.ObjectInfo {
l.mtx.RLock() l.mtx.RLock()
defer l.mtx.RUnlock() defer l.mtx.RUnlock()
if val, ok := l.caches[key]; ok { if val, ok := l.caches[key]; ok {
@ -67,7 +68,7 @@ func (l *listObjectsCache) Get(key cacheOptions) []*ObjectInfo {
return nil return nil
} }
func (l *listObjectsCache) Put(key cacheOptions, objects []*ObjectInfo) { func (l *listObjectsCache) Put(key cacheOptions, objects []*api.ObjectInfo) {
if len(objects) == 0 { if len(objects) == 0 {
return return
} }

View file

@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -29,11 +30,11 @@ func randSHA256Checksum(t *testing.T) (cs [sha256.Size]byte) {
func TestTrimAfterObjectName(t *testing.T) { func TestTrimAfterObjectName(t *testing.T) {
var ( var (
objects []*ObjectInfo objects []*api.ObjectInfo
names = []string{"b", "c", "d"} names = []string{"b", "c", "d"}
) )
for _, name := range names { for _, name := range names {
objects = append(objects, &ObjectInfo{Name: name}) objects = append(objects, &api.ObjectInfo{Name: name})
} }
t.Run("startafter before all objects", func(t *testing.T) { t.Run("startafter before all objects", func(t *testing.T) {
@ -62,7 +63,7 @@ func TestTrimAfterObjectName(t *testing.T) {
}) })
t.Run("empty objects", func(t *testing.T) { t.Run("empty objects", func(t *testing.T) {
actual := trimAfterObjectName(names[0], []*ObjectInfo{}) actual := trimAfterObjectName(names[0], []*api.ObjectInfo{})
require.Nil(t, actual) require.Nil(t, actual)
}) })
@ -79,14 +80,14 @@ func TestTrimAfterObjectName(t *testing.T) {
func TestTrimAfterObjectID(t *testing.T) { func TestTrimAfterObjectID(t *testing.T) {
var ( var (
objects []*ObjectInfo objects []*api.ObjectInfo
ids []*object.ID ids []*object.ID
numberOfIDS = 3 numberOfIDS = 3
) )
for i := 0; i < numberOfIDS; i++ { for i := 0; i < numberOfIDS; i++ {
id := randID(t) id := randID(t)
objects = append(objects, &ObjectInfo{id: id}) objects = append(objects, &api.ObjectInfo{ID: id})
ids = append(ids, id) ids = append(ids, id)
} }
@ -119,13 +120,13 @@ func TestTrimAfterObjectID(t *testing.T) {
func TestObjectsListCache(t *testing.T) { func TestObjectsListCache(t *testing.T) {
var ( var (
cacheSize = 10 cacheSize = 10
objects []*ObjectInfo objects []*api.ObjectInfo
userKey = "key" userKey = "key"
) )
for i := 0; i < cacheSize; i++ { for i := 0; i < cacheSize; i++ {
id := randID(t) id := randID(t)
objects = append(objects, &ObjectInfo{id: id, Name: id.String()}) objects = append(objects, &api.ObjectInfo{ID: id, Name: id.String()})
} }
sort.Slice(objects, func(i, j int) bool { sort.Slice(objects, func(i, j int) bool {

View file

@ -8,36 +8,16 @@ import (
"strings" "strings"
"time" "time"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/nspcc-dev/neofs-s3-gw/api" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox" "github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
) )
type ( type (
// ObjectInfo holds S3 object data.
ObjectInfo struct {
id *object.ID
bucketID *cid.ID
isDir bool
Bucket string
Name string
Size int64
ContentType string
Created time.Time
CreationEpoch uint64
HashSum string
Owner *owner.ID
Headers map[string]string
}
// ListObjectsInfo contains common fields of data for ListObjectsV1 and ListObjectsV2. // ListObjectsInfo contains common fields of data for ListObjectsV1 and ListObjectsV2.
ListObjectsInfo struct { ListObjectsInfo struct {
Prefixes []string Prefixes []string
Objects []*ObjectInfo Objects []*api.ObjectInfo
IsTruncated bool IsTruncated bool
} }
@ -55,7 +35,7 @@ type (
// ObjectVersionInfo stores info about objects versions. // ObjectVersionInfo stores info about objects versions.
ObjectVersionInfo struct { ObjectVersionInfo struct {
Object *ObjectInfo Object *api.ObjectInfo
IsLatest bool IsLatest bool
} }
@ -85,11 +65,11 @@ func userHeaders(attrs []*object.Attribute) map[string]string {
return result return result
} }
func objInfoFromMeta(bkt *cache.BucketInfo, meta *object.Object) *ObjectInfo { func objInfoFromMeta(bkt *api.BucketInfo, meta *object.Object) *api.ObjectInfo {
return objectInfoFromMeta(bkt, meta, "", "") return objectInfoFromMeta(bkt, meta, "", "")
} }
func objectInfoFromMeta(bkt *cache.BucketInfo, meta *object.Object, prefix, delimiter string) *ObjectInfo { func objectInfoFromMeta(bkt *api.BucketInfo, meta *object.Object, prefix, delimiter string) *api.ObjectInfo {
var ( var (
isDir bool isDir bool
size int64 size int64
@ -130,10 +110,10 @@ func objectInfoFromMeta(bkt *cache.BucketInfo, meta *object.Object, prefix, deli
size = int64(meta.PayloadSize()) size = int64(meta.PayloadSize())
} }
return &ObjectInfo{ return &api.ObjectInfo{
id: meta.ID(), ID: meta.ID(),
bucketID: bkt.CID, CID: bkt.CID,
isDir: isDir, IsDir: isDir,
Bucket: bkt.Name, Bucket: bkt.Name,
Name: filename, Name: filename,
@ -163,27 +143,6 @@ func NameFromString(name string) (string, string) {
return name[ind+1:], name[:ind+1] return name[ind+1:], name[:ind+1]
} }
// ID returns object ID from ObjectInfo.
func (o *ObjectInfo) ID() *object.ID { return o.id }
// Version returns object version from ObjectInfo.
func (o *ObjectInfo) Version() string { return o.id.String() }
// NiceName returns object name for cache.
func (o *ObjectInfo) NiceName() string { return o.Bucket + "/" + o.Name }
// Address returns object address.
func (o *ObjectInfo) Address() *object.Address { return newAddress(o.bucketID, o.id) }
// TagsObject returns name of system object for tags.
func (o *ObjectInfo) TagsObject() string { return ".tagset." + o.Name + "." + o.Version() }
// CID returns bucket ID from ObjectInfo.
func (o *ObjectInfo) CID() *cid.ID { return o.bucketID }
// IsDir allows to check if object is a directory.
func (o *ObjectInfo) IsDir() bool { return o.isDir }
// GetBoxData extracts accessbox.Box from context. // GetBoxData extracts accessbox.Box from context.
func GetBoxData(ctx context.Context) (*accessbox.Box, error) { func GetBoxData(ctx context.Context) (*accessbox.Box, error) {
var boxData *accessbox.Box var boxData *accessbox.Box

View file

@ -9,7 +9,7 @@ import (
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id" cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-api-go/pkg/owner" "github.com/nspcc-dev/neofs-api-go/pkg/owner"
"github.com/nspcc-dev/neofs-s3-gw/api/cache" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -20,7 +20,7 @@ var (
defaultTestContentType = http.DetectContentType(defaultTestPayload) defaultTestContentType = http.DetectContentType(defaultTestPayload)
) )
func newTestObject(oid *object.ID, bkt *cache.BucketInfo, name string) *object.Object { func newTestObject(oid *object.ID, bkt *api.BucketInfo, name string) *object.Object {
filename := object.NewAttribute() filename := object.NewAttribute()
filename.SetKey(object.AttributeFileName) filename.SetKey(object.AttributeFileName)
filename.SetValue(name) filename.SetValue(name)
@ -44,12 +44,12 @@ func newTestObject(oid *object.ID, bkt *cache.BucketInfo, name string) *object.O
return raw.Object() return raw.Object()
} }
func newTestInfo(oid *object.ID, bkt *cache.BucketInfo, name string, isDir bool) *ObjectInfo { func newTestInfo(oid *object.ID, bkt *api.BucketInfo, name string, isDir bool) *api.ObjectInfo {
info := &ObjectInfo{ info := &api.ObjectInfo{
id: oid, ID: oid,
Name: name, Name: name,
Bucket: bkt.Name, Bucket: bkt.Name,
bucketID: bkt.CID, CID: bkt.CID,
Size: defaultTestPayloadLength, Size: defaultTestPayloadLength,
ContentType: defaultTestContentType, ContentType: defaultTestContentType,
Created: time.Unix(defaultTestCreated.Unix(), 0), Created: time.Unix(defaultTestCreated.Unix(), 0),
@ -58,7 +58,7 @@ func newTestInfo(oid *object.ID, bkt *cache.BucketInfo, name string, isDir bool)
} }
if isDir { if isDir {
info.isDir = true info.IsDir = true
info.Size = 0 info.Size = 0
info.ContentType = "" info.ContentType = ""
info.Headers = nil info.Headers = nil
@ -72,7 +72,7 @@ func Test_objectInfoFromMeta(t *testing.T) {
oid := object.NewID() oid := object.NewID()
containerID := cid.New() containerID := cid.New()
bkt := &cache.BucketInfo{ bkt := &api.BucketInfo{
Name: "test-container", Name: "test-container",
CID: containerID, CID: containerID,
Owner: uid, Owner: uid,
@ -82,7 +82,7 @@ func Test_objectInfoFromMeta(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
prefix string prefix string
result *ObjectInfo result *api.ObjectInfo
object *object.Object object *object.Object
delimiter string delimiter string
}{ }{

View file

@ -7,13 +7,13 @@ import (
"strings" "strings"
"github.com/nspcc-dev/neofs-api-go/pkg/object" "github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-s3-gw/api/cache" "github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/errors" "github.com/nspcc-dev/neofs-s3-gw/api/errors"
) )
type objectVersions struct { type objectVersions struct {
name string name string
objects []*ObjectInfo objects []*api.ObjectInfo
addList []string addList []string
delList []string delList []string
isSorted bool isSorted bool
@ -34,7 +34,7 @@ func newObjectVersions(name string) *objectVersions {
return &objectVersions{name: name} return &objectVersions{name: name}
} }
func (v *objectVersions) appendVersion(oi *ObjectInfo) { func (v *objectVersions) appendVersion(oi *api.ObjectInfo) {
addVers := append(splitVersions(oi.Headers[versionsAddAttr]), oi.Version()) addVers := append(splitVersions(oi.Headers[versionsAddAttr]), oi.Version())
delVers := splitVersions(oi.Headers[versionsDelAttr]) delVers := splitVersions(oi.Headers[versionsDelAttr])
v.objects = append(v.objects, oi) v.objects = append(v.objects, oi)
@ -60,7 +60,7 @@ func (v *objectVersions) sort() {
} }
} }
func (v *objectVersions) getLast() *ObjectInfo { func (v *objectVersions) getLast() *api.ObjectInfo {
if len(v.objects) == 0 { if len(v.objects) == 0 {
return nil return nil
} }
@ -82,14 +82,14 @@ func (v *objectVersions) getLast() *ObjectInfo {
return nil return nil
} }
func (v *objectVersions) getFiltered() []*ObjectInfo { func (v *objectVersions) getFiltered() []*api.ObjectInfo {
if len(v.objects) == 0 { if len(v.objects) == 0 {
return nil return nil
} }
v.sort() v.sort()
existedVersions := getExistedVersions(v) existedVersions := getExistedVersions(v)
res := make([]*ObjectInfo, 0, len(v.objects)) res := make([]*api.ObjectInfo, 0, len(v.objects))
for _, version := range v.objects { for _, version := range v.objects {
delMark := version.Headers[versionsDeleteMarkAttr] delMark := version.Headers[versionsDeleteMarkAttr]
@ -109,15 +109,15 @@ func (v *objectVersions) getDelHeader() string {
return strings.Join(v.delList, ",") return strings.Join(v.delList, ",")
} }
func (v *objectVersions) getVersion(oid *object.ID) *ObjectInfo { func (v *objectVersions) getVersion(oid *object.ID) *api.ObjectInfo {
for _, version := range v.objects { for _, version := range v.objects {
if version.ID() == oid { if version.ID == oid {
return version return version
} }
} }
return nil return nil
} }
func (n *layer) PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*ObjectInfo, error) { func (n *layer) PutBucketVersioning(ctx context.Context, p *PutVersioningParams) (*api.ObjectInfo, error) {
bktInfo, err := n.GetBucketInfo(ctx, p.Bucket) bktInfo, err := n.GetBucketInfo(ctx, p.Bucket)
if err != nil { if err != nil {
return nil, err return nil, err
@ -171,13 +171,13 @@ func (n *layer) ListObjectVersions(ctx context.Context, p *ListObjectVersionsPar
} }
sort.Strings(sortedNames) sort.Strings(sortedNames)
allObjects = make([]*ObjectInfo, 0, p.MaxKeys) allObjects = make([]*api.ObjectInfo, 0, p.MaxKeys)
for _, name := range sortedNames { for _, name := range sortedNames {
allObjects = append(allObjects, versions[name].getFiltered()...) allObjects = append(allObjects, versions[name].getFiltered()...)
} }
// putting to cache a copy of allObjects because allObjects can be modified further // putting to cache a copy of allObjects because allObjects can be modified further
n.listsCache.Put(cacheKey, append([]*ObjectInfo(nil), allObjects...)) n.listsCache.Put(cacheKey, append([]*api.ObjectInfo(nil), allObjects...))
} }
for i, obj := range allObjects { for i, obj := range allObjects {
@ -230,7 +230,7 @@ func triageVersions(objVersions []*ObjectVersionInfo) ([]*ObjectVersionInfo, []*
return resVersion, resDelMarkVersions return resVersion, resDelMarkVersions
} }
func less(ov1, ov2 *ObjectInfo) bool { func less(ov1, ov2 *api.ObjectInfo) bool {
if ov1.CreationEpoch == ov2.CreationEpoch { if ov1.CreationEpoch == ov2.CreationEpoch {
return ov1.Version() < ov2.Version() return ov1.Version() < ov2.Version()
} }
@ -246,7 +246,7 @@ func contains(list []string, elem string) bool {
return false return false
} }
func (n *layer) getBucketSettings(ctx context.Context, bktInfo *cache.BucketInfo) (*BucketSettings, error) { func (n *layer) getBucketSettings(ctx context.Context, bktInfo *api.BucketInfo) (*BucketSettings, error) {
objInfo, err := n.getSystemObject(ctx, bktInfo, bktInfo.SettingsObjectName()) objInfo, err := n.getSystemObject(ctx, bktInfo, bktInfo.SettingsObjectName())
if err != nil { if err != nil {
return nil, err return nil, err
@ -255,7 +255,7 @@ func (n *layer) getBucketSettings(ctx context.Context, bktInfo *cache.BucketInfo
return objectInfoToBucketSettings(objInfo), nil return objectInfoToBucketSettings(objInfo), nil
} }
func objectInfoToBucketSettings(info *ObjectInfo) *BucketSettings { func objectInfoToBucketSettings(info *api.ObjectInfo) *BucketSettings {
res := &BucketSettings{} res := &BucketSettings{}
enabled, ok := info.Headers[attrSettingsVersioningEnabled] enabled, ok := info.Headers[attrSettingsVersioningEnabled]
@ -267,7 +267,7 @@ func objectInfoToBucketSettings(info *ObjectInfo) *BucketSettings {
return res return res
} }
func (n *layer) checkVersionsExist(ctx context.Context, bkt *cache.BucketInfo, obj *VersionedObject) (*object.ID, error) { func (n *layer) checkVersionsExist(ctx context.Context, bkt *api.BucketInfo, obj *VersionedObject) (*object.ID, error) {
id := object.NewID() id := object.NewID()
if err := id.Parse(obj.VersionID); err != nil { if err := id.Parse(obj.VersionID); err != nil {
return nil, errors.GetAPIError(errors.ErrInvalidVersion) return nil, errors.GetAPIError(errors.ErrInvalidVersion)

View file

@ -207,7 +207,7 @@ func (t *testPool) WaitForContainerPresence(ctx context.Context, id *cid.ID, par
return nil return nil
} }
func (tc *testContext) putObject(content []byte) *ObjectInfo { func (tc *testContext) putObject(content []byte) *api.ObjectInfo {
objInfo, err := tc.layer.PutObject(tc.ctx, &PutObjectParams{ objInfo, err := tc.layer.PutObject(tc.ctx, &PutObjectParams{
Bucket: tc.bkt, Bucket: tc.bkt,
Object: tc.obj, Object: tc.obj,
@ -220,7 +220,7 @@ func (tc *testContext) putObject(content []byte) *ObjectInfo {
return objInfo return objInfo
} }
func (tc *testContext) getObject(objectName, versionID string, needError bool) (*ObjectInfo, []byte) { func (tc *testContext) getObject(objectName, versionID string, needError bool) (*api.ObjectInfo, []byte) {
objInfo, err := tc.layer.GetObjectInfo(tc.ctx, &HeadObjectParams{ objInfo, err := tc.layer.GetObjectInfo(tc.ctx, &HeadObjectParams{
Bucket: tc.bkt, Bucket: tc.bkt,
Object: objectName, Object: objectName,
@ -252,7 +252,7 @@ func (tc *testContext) deleteObject(objectName, versionID string) {
} }
} }
func (tc *testContext) listObjectsV1() []*ObjectInfo { func (tc *testContext) listObjectsV1() []*api.ObjectInfo {
res, err := tc.layer.ListObjectsV1(tc.ctx, &ListObjectsParamsV1{ res, err := tc.layer.ListObjectsV1(tc.ctx, &ListObjectsParamsV1{
ListObjectsParamsCommon: ListObjectsParamsCommon{ ListObjectsParamsCommon: ListObjectsParamsCommon{
Bucket: tc.bkt, Bucket: tc.bkt,
@ -263,7 +263,7 @@ func (tc *testContext) listObjectsV1() []*ObjectInfo {
return res.Objects return res.Objects
} }
func (tc *testContext) listObjectsV2() []*ObjectInfo { func (tc *testContext) listObjectsV2() []*api.ObjectInfo {
res, err := tc.layer.ListObjectsV2(tc.ctx, &ListObjectsParamsV2{ res, err := tc.layer.ListObjectsV2(tc.ctx, &ListObjectsParamsV2{
ListObjectsParamsCommon: ListObjectsParamsCommon{ ListObjectsParamsCommon: ListObjectsParamsCommon{
Bucket: tc.bkt, Bucket: tc.bkt,
@ -357,12 +357,12 @@ func TestSimpleVersioning(t *testing.T) {
objv2, buffer2 := tc.getObject(tc.obj, "", false) objv2, buffer2 := tc.getObject(tc.obj, "", false)
require.Equal(t, obj1Content2, buffer2) require.Equal(t, obj1Content2, buffer2)
require.Contains(t, objv2.Headers[versionsAddAttr], obj1v1.ID().String()) require.Contains(t, objv2.Headers[versionsAddAttr], obj1v1.ID.String())
_, buffer1 := tc.getObject(tc.obj, obj1v1.ID().String(), false) _, buffer1 := tc.getObject(tc.obj, obj1v1.ID.String(), false)
require.Equal(t, obj1Content1, buffer1) require.Equal(t, obj1Content1, buffer1)
tc.checkListObjects(obj1v2.ID()) tc.checkListObjects(obj1v2.ID)
} }
func TestSimpleNoVersioning(t *testing.T) { func TestSimpleNoVersioning(t *testing.T) {
@ -376,10 +376,10 @@ func TestSimpleNoVersioning(t *testing.T) {
objv2, buffer2 := tc.getObject(tc.obj, "", false) objv2, buffer2 := tc.getObject(tc.obj, "", false)
require.Equal(t, obj1Content2, buffer2) require.Equal(t, obj1Content2, buffer2)
require.Contains(t, objv2.Headers[versionsDelAttr], obj1v1.ID().String()) require.Contains(t, objv2.Headers[versionsDelAttr], obj1v1.ID.String())
tc.getObject(tc.obj, obj1v1.ID().String(), true) tc.getObject(tc.obj, obj1v1.ID.String(), true)
tc.checkListObjects(obj1v2.ID()) tc.checkListObjects(obj1v2.ID)
} }
func TestVersioningDeleteObject(t *testing.T) { func TestVersioningDeleteObject(t *testing.T) {
@ -454,7 +454,7 @@ func TestGetLastVersion(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
versions *objectVersions versions *objectVersions
expected *ObjectInfo expected *api.ObjectInfo
}{ }{
{ {
versions: &objectVersions{}, versions: &objectVersions{},
@ -462,21 +462,21 @@ func TestGetLastVersion(t *testing.T) {
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj2, obj1}, objects: []*api.ObjectInfo{obj2, obj1},
addList: []string{obj1.Version(), obj2.Version()}, addList: []string{obj1.Version(), obj2.Version()},
}, },
expected: obj2, expected: obj2,
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj2, obj1, obj3}, objects: []*api.ObjectInfo{obj2, obj1, obj3},
addList: []string{obj1.Version(), obj2.Version(), obj3.Version()}, addList: []string{obj1.Version(), obj2.Version(), obj3.Version()},
}, },
expected: nil, expected: nil,
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj2, obj1, obj4}, objects: []*api.ObjectInfo{obj2, obj1, obj4},
addList: []string{obj1.Version(), obj2.Version(), obj4.Version()}, addList: []string{obj1.Version(), obj2.Version(), obj4.Version()},
delList: []string{obj2.Version()}, delList: []string{obj2.Version()},
}, },
@ -484,7 +484,7 @@ func TestGetLastVersion(t *testing.T) {
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj1, obj5}, objects: []*api.ObjectInfo{obj1, obj5},
addList: []string{obj1.Version(), obj5.Version()}, addList: []string{obj1.Version(), obj5.Version()},
delList: []string{obj1.Version()}, delList: []string{obj1.Version()},
}, },
@ -492,13 +492,13 @@ func TestGetLastVersion(t *testing.T) {
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj5}, objects: []*api.ObjectInfo{obj5},
}, },
expected: nil, expected: nil,
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj1, obj2, obj3, obj6}, objects: []*api.ObjectInfo{obj1, obj2, obj3, obj6},
addList: []string{obj1.Version(), obj2.Version(), obj3.Version(), obj6.Version()}, addList: []string{obj1.Version(), obj2.Version(), obj3.Version(), obj6.Version()},
delList: []string{obj3.Version()}, delList: []string{obj3.Version()},
}, },
@ -506,7 +506,7 @@ func TestGetLastVersion(t *testing.T) {
}, },
{ {
versions: &objectVersions{ versions: &objectVersions{
objects: []*ObjectInfo{obj1, obj1V2}, objects: []*api.ObjectInfo{obj1, obj1V2},
addList: []string{obj1.Version(), obj1V2.Version()}, addList: []string{obj1.Version(), obj1V2.Version()},
}, },
// creation epochs are equal // creation epochs are equal
@ -527,38 +527,38 @@ func TestAppendVersions(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
versions *objectVersions versions *objectVersions
objectToAdd *ObjectInfo objectToAdd *api.ObjectInfo
expectedVersions *objectVersions expectedVersions *objectVersions
}{ }{
{ {
versions: &objectVersions{}, versions: &objectVersions{},
objectToAdd: obj1, objectToAdd: obj1,
expectedVersions: &objectVersions{ expectedVersions: &objectVersions{
objects: []*ObjectInfo{obj1}, objects: []*api.ObjectInfo{obj1},
addList: []string{obj1.Version()}, addList: []string{obj1.Version()},
}, },
}, },
{ {
versions: &objectVersions{objects: []*ObjectInfo{obj1}}, versions: &objectVersions{objects: []*api.ObjectInfo{obj1}},
objectToAdd: obj2, objectToAdd: obj2,
expectedVersions: &objectVersions{ expectedVersions: &objectVersions{
objects: []*ObjectInfo{obj1, obj2}, objects: []*api.ObjectInfo{obj1, obj2},
addList: []string{obj1.Version(), obj2.Version()}, addList: []string{obj1.Version(), obj2.Version()},
}, },
}, },
{ {
versions: &objectVersions{objects: []*ObjectInfo{obj1, obj2}}, versions: &objectVersions{objects: []*api.ObjectInfo{obj1, obj2}},
objectToAdd: obj3, objectToAdd: obj3,
expectedVersions: &objectVersions{ expectedVersions: &objectVersions{
objects: []*ObjectInfo{obj1, obj2, obj3}, objects: []*api.ObjectInfo{obj1, obj2, obj3},
addList: []string{obj1.Version(), obj2.Version(), obj3.Version()}, addList: []string{obj1.Version(), obj2.Version(), obj3.Version()},
}, },
}, },
{ {
versions: &objectVersions{objects: []*ObjectInfo{obj1, obj2}}, versions: &objectVersions{objects: []*api.ObjectInfo{obj1, obj2}},
objectToAdd: obj4, objectToAdd: obj4,
expectedVersions: &objectVersions{ expectedVersions: &objectVersions{
objects: []*ObjectInfo{obj1, obj2, obj4}, objects: []*api.ObjectInfo{obj1, obj2, obj4},
addList: []string{obj1.Version(), obj2.Version(), obj4.Version()}, addList: []string{obj1.Version(), obj2.Version(), obj4.Version()},
delList: []string{obj2.Version()}, delList: []string{obj2.Version()},
}, },
@ -569,7 +569,7 @@ func TestAppendVersions(t *testing.T) {
} }
} }
func joinVers(objs ...*ObjectInfo) string { func joinVers(objs ...*api.ObjectInfo) string {
if len(objs) == 0 { if len(objs) == 0 {
return "" return ""
} }
@ -590,7 +590,7 @@ func getOID(id byte) *object.ID {
return oid return oid
} }
func getTestObjectInfo(epoch uint64, oid *object.ID, addAttr, delAttr, delMarkAttr string) *ObjectInfo { func getTestObjectInfo(epoch uint64, oid *object.ID, addAttr, delAttr, delMarkAttr string) *api.ObjectInfo {
headers := make(map[string]string) headers := make(map[string]string)
if addAttr != "" { if addAttr != "" {
headers[versionsAddAttr] = addAttr headers[versionsAddAttr] = addAttr
@ -602,8 +602,8 @@ func getTestObjectInfo(epoch uint64, oid *object.ID, addAttr, delAttr, delMarkAt
headers[versionsDeleteMarkAttr] = delMarkAttr headers[versionsDeleteMarkAttr] = delMarkAttr
} }
return &ObjectInfo{ return &api.ObjectInfo{
id: oid, ID: oid,
CreationEpoch: epoch, CreationEpoch: epoch,
Headers: headers, Headers: headers,
} }