forked from TrueCloudLab/frostfs-rest-gw
parent
c7c570fd10
commit
dc1926f9c6
18 changed files with 1837 additions and 126 deletions
|
@ -66,6 +66,7 @@ func (a *API) Configure(api *operations.NeofsRestGwAPI) http.Handler {
|
|||
api.PutObjectHandler = operations.PutObjectHandlerFunc(a.PutObjects)
|
||||
api.GetObjectInfoHandler = operations.GetObjectInfoHandlerFunc(a.GetObjectInfo)
|
||||
api.DeleteObjectHandler = operations.DeleteObjectHandlerFunc(a.DeleteObject)
|
||||
api.SearchObjectsHandler = operations.SearchObjectsHandlerFunc(a.SearchObjects)
|
||||
|
||||
api.PutContainerHandler = operations.PutContainerHandlerFunc(a.PutContainers)
|
||||
api.GetContainerHandler = operations.GetContainerHandlerFunc(a.GetContainer)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
@ -67,7 +68,7 @@ func (a *API) PutObjects(params operations.PutObjectParams, principal *models.Pr
|
|||
return errorResponse.WithPayload(NewError(err))
|
||||
}
|
||||
|
||||
var resp operations.PutObjectOKBody
|
||||
var resp models.Address
|
||||
resp.ContainerID = params.Object.ContainerID
|
||||
resp.ObjectID = NewString(objID.String())
|
||||
|
||||
|
@ -144,6 +145,109 @@ func (a *API) DeleteObject(params operations.DeleteObjectParams, principal *mode
|
|||
return operations.NewDeleteObjectNoContent()
|
||||
}
|
||||
|
||||
// SearchObjects handler that removes object from NeoFS.
|
||||
func (a *API) SearchObjects(params operations.SearchObjectsParams, principal *models.Principal) middleware.Responder {
|
||||
errorResponse := operations.NewSearchObjectsBadRequest()
|
||||
ctx := params.HTTPRequest.Context()
|
||||
|
||||
var cnrID cid.ID
|
||||
if err := cnrID.Parse(params.ContainerID); err != nil {
|
||||
a.log.Error("invalid container id", zap.Error(err))
|
||||
return errorResponse.WithPayload("invalid container id")
|
||||
}
|
||||
|
||||
btoken, err := getBearerToken(principal, params.XBearerSignature, params.XBearerSignatureKey, *params.WalletConnect)
|
||||
if err != nil {
|
||||
a.log.Error("failed to get bearer token", zap.Error(err))
|
||||
return errorResponse.WithPayload(NewError(err))
|
||||
}
|
||||
|
||||
filters, err := ToNativeFilters(params.SearchFilters)
|
||||
if err != nil {
|
||||
a.log.Error("failed to transform to native", zap.Error(err))
|
||||
return errorResponse.WithPayload(NewError(err))
|
||||
}
|
||||
|
||||
var prm pool.PrmObjectSearch
|
||||
prm.SetContainerID(cnrID)
|
||||
prm.UseBearer(btoken)
|
||||
prm.SetFilters(filters)
|
||||
|
||||
resSearch, err := a.pool.SearchObjects(ctx, prm)
|
||||
if err != nil {
|
||||
a.log.Error("failed to search objects", zap.Error(err))
|
||||
return errorResponse.WithPayload(NewError(err))
|
||||
}
|
||||
|
||||
offset := int(*params.Offset)
|
||||
size := int(*params.Limit)
|
||||
|
||||
var iterateErr error
|
||||
var obj *models.ObjectBaseInfo
|
||||
var objects []*models.ObjectBaseInfo
|
||||
|
||||
i := 0
|
||||
err = resSearch.Iterate(func(id oid.ID) bool {
|
||||
if i < offset {
|
||||
i++
|
||||
return false
|
||||
}
|
||||
|
||||
if obj, iterateErr = headObjectBaseInfo(ctx, a.pool, &cnrID, &id, btoken); iterateErr != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
objects = append(objects, obj)
|
||||
|
||||
return len(objects) == size
|
||||
})
|
||||
if err == nil {
|
||||
err = iterateErr
|
||||
}
|
||||
if err != nil {
|
||||
a.log.Error("failed to search objects", zap.Error(err))
|
||||
return errorResponse.WithPayload(NewError(err))
|
||||
}
|
||||
|
||||
list := &models.ObjectList{
|
||||
Size: NewInteger(int64(len(objects))),
|
||||
Objects: objects,
|
||||
}
|
||||
|
||||
return operations.NewSearchObjectsOK().WithPayload(list)
|
||||
}
|
||||
|
||||
func headObjectBaseInfo(ctx context.Context, p *pool.Pool, cnrID *cid.ID, objID *oid.ID, btoken *token.BearerToken) (*models.ObjectBaseInfo, error) {
|
||||
addr := address.NewAddress()
|
||||
addr.SetContainerID(cnrID)
|
||||
addr.SetObjectID(objID)
|
||||
|
||||
var prm pool.PrmObjectHead
|
||||
prm.SetAddress(*addr)
|
||||
prm.UseBearer(btoken)
|
||||
|
||||
objInfo, err := p.HeadObject(ctx, prm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &models.ObjectBaseInfo{
|
||||
Address: &models.Address{
|
||||
ContainerID: NewString(cnrID.String()),
|
||||
ObjectID: NewString(objID.String()),
|
||||
},
|
||||
}
|
||||
|
||||
for _, attr := range objInfo.Attributes() {
|
||||
if attr.Key() == object.AttributeFileName {
|
||||
resp.Name = attr.Value()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func parseAddress(containerID, objectID string) (*address.Address, error) {
|
||||
var cnrID cid.ID
|
||||
if err := cnrID.Parse(containerID); err != nil {
|
||||
|
|
|
@ -3,6 +3,7 @@ package handlers
|
|||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/nspcc-dev/neofs-sdk-go/object"
|
||||
|
||||
sessionv2 "github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||
"github.com/nspcc-dev/neofs-rest-gw/gen/models"
|
||||
|
@ -391,3 +392,40 @@ func ToNativeTable(records []*models.Record) (*eacl.Table, error) {
|
|||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
// ToNativeMatchFilter converts models.SearchMatch to object.SearchMatchType.
|
||||
func ToNativeMatchFilter(s *models.SearchMatch) (object.SearchMatchType, error) {
|
||||
if s == nil {
|
||||
return object.MatchUnknown, fmt.Errorf("unsupported empty verb type")
|
||||
}
|
||||
|
||||
switch *s {
|
||||
case models.SearchMatchMatchStringEqual:
|
||||
return object.MatchStringEqual, nil
|
||||
case models.SearchMatchMatchStringNotEqual:
|
||||
return object.MatchStringNotEqual, nil
|
||||
case models.SearchMatchMatchNotPresent:
|
||||
return object.MatchNotPresent, nil
|
||||
case models.SearchMatchMatchCommonPrefix:
|
||||
return object.MatchCommonPrefix, nil
|
||||
default:
|
||||
return object.MatchUnknown, fmt.Errorf("unsupported search match: '%s'", *s)
|
||||
}
|
||||
}
|
||||
|
||||
// ToNativeFilters converts models.SearchFilters to object.SearchFilters.
|
||||
func ToNativeFilters(fs *models.SearchFilters) (object.SearchFilters, error) {
|
||||
filters := object.NewSearchFilters()
|
||||
filters.AddRootFilter()
|
||||
|
||||
for _, f := range fs.Filters {
|
||||
matchFilter, err := ToNativeMatchFilter(f.Match)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filters.AddFilter(*f.Key, *f.Value, matchFilter)
|
||||
}
|
||||
|
||||
return filters, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue