[#121] Fixed directory listing

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-07-01 13:54:51 +03:00
parent 7ebcd5af8f
commit 42384730a0
3 changed files with 24 additions and 2 deletions

View file

@ -126,6 +126,7 @@ func (h *handler) listObjects(w http.ResponseWriter, r *http.Request) (*listObje
MaxKeys: arg.MaxKeys, MaxKeys: arg.MaxKeys,
Delimiter: arg.Delimiter, Delimiter: arg.Delimiter,
Marker: marker, Marker: marker,
Version: arg.APIVersion,
}) })
if err != nil { if err != nil {
h.log.Error("something went wrong", h.log.Error("something went wrong",

View file

@ -32,6 +32,7 @@ type (
Delimiter string Delimiter string
MaxKeys int MaxKeys int
Marker string Marker string
Version int
} }
) )

View file

@ -8,6 +8,7 @@ import (
"io" "io"
"net/url" "net/url"
"sort" "sort"
"strings"
"time" "time"
"github.com/nspcc-dev/neofs-api-go/pkg/client" "github.com/nspcc-dev/neofs-api-go/pkg/client"
@ -116,6 +117,9 @@ var (
ErrObjectNotExists = errors.New("object not exists") ErrObjectNotExists = errors.New("object not exists")
) )
// ETag (hex encoded md5sum) of empty string.
const emptyETag = "d41d8cd98f00b204e9800998ecf8427e"
// NewLayer creates instance of layer. It checks credentials // NewLayer creates instance of layer. It checks credentials
// and establishes gRPC connection with node. // and establishes gRPC connection with node.
func NewLayer(log *zap.Logger, conns pool.Pool) Client { func NewLayer(log *zap.Logger, conns pool.Pool) Client {
@ -216,6 +220,8 @@ func (n *layer) ListObjects(ctx context.Context, p *ListObjectsParams) (*ListObj
ln = p.MaxKeys ln = p.MaxKeys
} }
mostRecentModified := time.Time{}
needDirectoryAsKey := p.Version == 2 && len(p.Prefix) > 0 && len(p.Delimiter) > 0 && strings.HasSuffix(p.Prefix, p.Delimiter)
result.Objects = make([]*ObjectInfo, 0, ln) result.Objects = make([]*ObjectInfo, 0, ln)
for _, id := range ids { for _, id := range ids {
@ -251,6 +257,9 @@ func (n *layer) ListObjects(ctx context.Context, p *ListObjectsParams) (*ListObj
// sub-entities, then it is a file, else directory. // sub-entities, then it is a file, else directory.
if oi := objectInfoFromMeta(bkt, meta, p.Prefix, p.Delimiter); oi != nil { if oi := objectInfoFromMeta(bkt, meta, p.Prefix, p.Delimiter); oi != nil {
if needDirectoryAsKey && oi.Created.After(mostRecentModified) {
mostRecentModified = oi.Created
}
// use only unique dir names // use only unique dir names
if _, ok := uniqNames[oi.Name]; ok { if _, ok := uniqNames[oi.Name]; ok {
continue continue
@ -275,12 +284,23 @@ func (n *layer) ListObjects(ctx context.Context, p *ListObjectsParams) (*ListObj
result.NextMarker = result.Objects[len(result.Objects)-1].Name result.NextMarker = result.Objects[len(result.Objects)-1].Name
} }
for i, oi := range result.Objects { index := 0
for _, oi := range result.Objects {
if isDir := uniqNames[oi.Name]; isDir { if isDir := uniqNames[oi.Name]; isDir {
result.Objects = append(result.Objects[:i], result.Objects[i+1:]...) result.Objects = append(result.Objects[:index], result.Objects[index+1:]...)
result.Prefixes = append(result.Prefixes, oi.Name) result.Prefixes = append(result.Prefixes, oi.Name)
} else {
index++
} }
} }
if needDirectoryAsKey {
res := []*ObjectInfo{{
Name: p.Prefix,
Created: mostRecentModified,
HashSum: emptyETag,
}}
result.Objects = append(res, result.Objects...)
}
return &result, nil return &result, nil
} }