diff --git a/client/api_object.go b/client/api_object.go index 9a354fbd..f4ba5fe8 100644 --- a/client/api_object.go +++ b/client/api_object.go @@ -59,6 +59,7 @@ type IObjectClient interface { ListObjects(ctx context.Context, bucketName string, opts types.ListObjectsOptions) (types.ListObjectsResult, error) ComputeHashRoots(reader io.Reader, isSerial bool) ([][]byte, int64, storageTypes.RedundancyType, error) CreateFolder(ctx context.Context, bucketName, objectName string, opts types.CreateObjectOptions) (string, error) + DelegateCreateFolder(ctx context.Context, bucketName, objectName string, opts types.PutObjectOptions) error GetObjectUploadProgress(ctx context.Context, bucketName, objectName string) (string, error) ListObjectsByObjectID(ctx context.Context, objectIds []uint64, opts types.EndPointOptions) (types.ListObjectsByObjectIDResponse, error) ListObjectPolicies(ctx context.Context, objectName, bucketName string, actionType uint32, opts types.ListObjectPoliciesOptions) (types.ListObjectPoliciesResponse, error) @@ -379,6 +380,47 @@ func (c *Client) putObject(ctx context.Context, bucketName, objectName string, o return nil } +func (c *Client) delegateCreateFolder(ctx context.Context, bucketName, objectName string, opts types.PutObjectOptions, +) (err error) { + + var contentType string + if opts.ContentType != "" { + contentType = opts.ContentType + } else { + contentType = types.ContentDefault + } + urlValues := make(url.Values) + + urlValues.Set("create-folder", "") + urlValues.Set("visibility", strconv.FormatInt(int64(opts.Visibility), 10)) + + reqMeta := requestMeta{ + bucketName: bucketName, + objectName: objectName, + contentSHA256: types.EmptyStringSHA256, + contentLength: 0, + contentType: contentType, + urlValues: urlValues, + } + + sendOpt := sendOptions{ + method: http.MethodPost, + } + + endpoint, err := c.getSPUrlByBucket(bucketName) + if err != nil { + log.Error().Msg(fmt.Sprintf("route endpoint by bucket: %s failed, err: %s", bucketName, err.Error())) + return err + } + + _, err = c.sendReq(ctx, reqMeta, &sendOpt, endpoint) + if err != nil { + return err + } + + return nil +} + // UploadSegmentHook is for testing usage type uploadSegmentHook func(id int) error @@ -1138,6 +1180,16 @@ func (c *Client) CreateFolder(ctx context.Context, bucketName, objectName string return txHash, err } +// DelegateCreateFolder send create empty object txn to greenfield chain +func (c *Client) DelegateCreateFolder(ctx context.Context, bucketName, objectName string, opts types.PutObjectOptions) error { + if !strings.HasSuffix(objectName, "/") { + return errors.New("failed to create folder. Folder names must end with a forward slash (/) character") + } + opts.Delegated = true + + return c.delegateCreateFolder(ctx, bucketName, objectName, opts) +} + // GetObjectUploadProgress return the status of object including the uploading progress func (c *Client) GetObjectUploadProgress(ctx context.Context, bucketName, objectName string) (string, error) { status, err := c.HeadObject(ctx, bucketName, objectName) diff --git a/e2e/e2e_storage_test.go b/e2e/e2e_storage_test.go index 6777570f..f8cca0e7 100644 --- a/e2e/e2e_storage_test.go +++ b/e2e/e2e_storage_test.go @@ -304,6 +304,7 @@ func (s *StorageTestSuite) Test_Object() { err = s.Client.DelegateUpdateObjectContent(s.ClientContext, bucketName, objectName2, newObjectSize, bytes.NewReader(newBuffer.Bytes()), types.PutObjectOptions{}) s.Require().NoError(err) s.WaitSealObject(bucketName, objectName2) + } func (s *StorageTestSuite) Test_Group() { @@ -953,6 +954,32 @@ func (s *StorageTestSuite) Test_Get_Object_With_ForcedSpEndpoint() { s.Client = origClient } +func (s *StorageTestSuite) TestCreateFolder() { + bucketName := storageTestUtil.GenRandomBucketName() + objectName := storageTestUtil.GenRandomObjectName() + objectName = fmt.Sprintf("%s/", objectName) + + s.T().Logf("BucketName:%s, objectName: %s", bucketName, objectName) + + bucketTx, err := s.Client.CreateBucket(s.ClientContext, bucketName, s.PrimarySP.OperatorAddress, types.CreateBucketOptions{Visibility: storageTypes.VISIBILITY_TYPE_PUBLIC_READ}) + s.Require().NoError(err) + + _, err = s.Client.WaitForTx(s.ClientContext, bucketTx) + s.Require().NoError(err) + + bucketInfo, err := s.Client.HeadBucket(s.ClientContext, bucketName) + s.Require().NoError(err) + if err == nil { + s.Require().Equal(bucketInfo.Visibility, storageTypes.VISIBILITY_TYPE_PUBLIC_READ) + } + + s.T().Log("---> CreateFolder and HeadObject <---") + err = s.Client.DelegateCreateFolder(s.ClientContext, bucketName, objectName, types.PutObjectOptions{Visibility: storageTypes.VISIBILITY_TYPE_PUBLIC_READ}) + s.Require().NoError(err) + + s.WaitSealObject(bucketName, objectName) +} + func (s *StorageTestSuite) PutObjectWithRetry(bucketName, objectName string, objectSize int64, buffer bytes.Buffer, option types.PutObjectOptions) error { var err error for retry := 0; retry < 5; retry++ {