github.com/qiniu/go-sdk/v7@v7.27.0/storagev2/objects/operations.go (about)

     1  package objects
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/qiniu/go-sdk/v7/storagev2/apis"
    13  	"github.com/qiniu/go-sdk/v7/storagev2/apis/stat_object"
    14  )
    15  
    16  type (
    17  	// 操作接口,用于发送单次请求或批量请求
    18  	Operation interface {
    19  		// 批量请求命令
    20  		fmt.Stringer
    21  		// 被操作的对象,必须返回至少一个
    22  		relatedEntries() []entry
    23  		// 处理返回结果
    24  		handleResponse(*ObjectDetails, error)
    25  	}
    26  
    27  	entry struct {
    28  		bucketName string
    29  		objectName string
    30  	}
    31  
    32  	// 获取对象元信息操作
    33  	StatObjectOperation struct {
    34  		object     Object
    35  		needParts  bool
    36  		onResponse func(*ObjectDetails)
    37  		onError    func(error)
    38  	}
    39  
    40  	// 移动对象操作
    41  	MoveObjectOperation struct {
    42  		fromObject Object
    43  		toObject   entry
    44  		force      bool
    45  		onResponse func()
    46  		onError    func(error)
    47  	}
    48  
    49  	// 复制对象操作
    50  	CopyObjectOperation struct {
    51  		fromObject Object
    52  		toObject   entry
    53  		force      bool
    54  		onResponse func()
    55  		onError    func(error)
    56  	}
    57  
    58  	// 删除对象操作
    59  	DeleteObjectOperation struct {
    60  		object     Object
    61  		onResponse func()
    62  		onError    func(error)
    63  	}
    64  
    65  	// 解冻对象操作
    66  	RestoreObjectOperation struct {
    67  		object          Object
    68  		freezeAfterDays int64
    69  		onResponse      func()
    70  		onError         func(error)
    71  	}
    72  
    73  	// 设置对象存储类型操作
    74  	SetObjectStorageClassOperation struct {
    75  		object       Object
    76  		storageClass StorageClass
    77  		onResponse   func()
    78  		onError      func(error)
    79  	}
    80  
    81  	// 设置对象状态
    82  	SetObjectStatusOperation struct {
    83  		object     Object
    84  		status     Status
    85  		onResponse func()
    86  		onError    func(error)
    87  	}
    88  
    89  	// 设置对象元信息操作
    90  	SetObjectMetadataOperation struct {
    91  		object     Object
    92  		mimeType   string
    93  		metadata   map[string]string
    94  		conditions map[string]string
    95  		onResponse func()
    96  		onError    func(error)
    97  	}
    98  
    99  	// 设置对象生命周期操作
   100  	SetObjectLifeCycleOperation struct {
   101  		object                 Object
   102  		toIAAfterDays          int64
   103  		toArchiveIRAfterDays   int64
   104  		toArchiveAfterDays     int64
   105  		toDeepArchiveAfterDays int64
   106  		deleteAfterDays        int64
   107  		onResponse             func()
   108  		onError                func(error)
   109  	}
   110  )
   111  
   112  func (operation *StatObjectOperation) NeedParts(needParts bool) *StatObjectOperation {
   113  	copy := *operation
   114  	copy.needParts = needParts
   115  	return &copy
   116  }
   117  
   118  func (operation *StatObjectOperation) OnResponse(fn func(*ObjectDetails)) *StatObjectOperation {
   119  	copy := *operation
   120  	copy.onResponse = fn
   121  	return &copy
   122  }
   123  
   124  func (operation *StatObjectOperation) OnError(fn func(error)) *StatObjectOperation {
   125  	copy := *operation
   126  	copy.onError = fn
   127  	return &copy
   128  }
   129  
   130  func (operation *StatObjectOperation) relatedEntries() []entry {
   131  	return []entry{{operation.object.bucket.name, operation.object.name}}
   132  }
   133  
   134  func (operation *StatObjectOperation) parseResponse(response *stat_object.Response, err error) (*ObjectDetails, error) {
   135  	if err != nil {
   136  		if operation.onError != nil {
   137  			operation.onError(err)
   138  		}
   139  		return nil, err
   140  	}
   141  
   142  	object := ObjectDetails{
   143  		Name:          operation.object.name,
   144  		UploadedAt:    time.Unix(response.PutTime/1e7, (response.PutTime%1e7)*1e2),
   145  		ETag:          response.Hash,
   146  		Size:          response.Size,
   147  		MimeType:      response.MimeType,
   148  		StorageClass:  StorageClass(response.Type),
   149  		EndUser:       response.EndUser,
   150  		Status:        Status(response.Status),
   151  		RestoreStatus: RestoreStatus(response.RestoringStatus),
   152  		Metadata:      response.Metadata,
   153  	}
   154  	var md5 []byte
   155  	if response.Md5 != "" {
   156  		md5, err = hex.DecodeString(response.Md5)
   157  		if err != nil {
   158  			if operation.onError != nil {
   159  				operation.onError(err)
   160  			}
   161  			return nil, err
   162  		}
   163  	}
   164  	if len(md5) > 0 {
   165  		copy(object.MD5[:], md5)
   166  	}
   167  	if len(response.Parts) > 0 {
   168  		object.Parts = append(make(stat_object.PartSizes, 0, len(response.Parts)), response.Parts...)
   169  	}
   170  	if response.TransitionToIaTime > 0 {
   171  		transitionToIA := time.Unix(response.TransitionToIaTime, 0)
   172  		object.TransitionToIA = &transitionToIA
   173  	}
   174  	if response.TransitionToArchiveIrTime > 0 {
   175  		transitionToArchiveIR := time.Unix(response.TransitionToArchiveIrTime, 0)
   176  		object.TransitionToArchiveIR = &transitionToArchiveIR
   177  	}
   178  	if response.TransitionToArchiveTime > 0 {
   179  		transitionToArchive := time.Unix(response.TransitionToArchiveTime, 0)
   180  		object.TransitionToArchive = &transitionToArchive
   181  	}
   182  	if response.TransitionToDeepArchiveTime > 0 {
   183  		transitionToDeepArchive := time.Unix(response.TransitionToDeepArchiveTime, 0)
   184  		object.TransitionToDeepArchive = &transitionToDeepArchive
   185  	}
   186  	if response.ExpirationTime > 0 {
   187  		expireAt := time.Unix(response.ExpirationTime, 0)
   188  		object.ExpireAt = &expireAt
   189  	}
   190  	if operation.onResponse != nil {
   191  		operation.onResponse(&object)
   192  	}
   193  	return &object, nil
   194  }
   195  
   196  func (operation *StatObjectOperation) handleResponse(object *ObjectDetails, err error) {
   197  	if err != nil && operation.onError != nil {
   198  		operation.onError(err)
   199  	} else if operation.onResponse != nil {
   200  		operation.onResponse(object)
   201  	}
   202  }
   203  
   204  func (operation *StatObjectOperation) String() string {
   205  	s := "stat/" + operation.object.encode()
   206  	if operation.needParts {
   207  		s += "/needparts/true"
   208  	}
   209  	return s
   210  }
   211  
   212  func (operation *StatObjectOperation) Call(ctx context.Context) (*ObjectDetails, error) {
   213  	response, err := operation.object.bucket.objectsManager.storage.StatObject(ctx, &apis.StatObjectRequest{
   214  		Entry:     operation.object.String(),
   215  		NeedParts: operation.needParts,
   216  	}, &apis.Options{
   217  		OverwrittenBucketName: operation.object.bucket.name,
   218  	})
   219  	return operation.parseResponse(response, err)
   220  }
   221  
   222  var _ Operation = (*StatObjectOperation)(nil)
   223  
   224  func (operation *MoveObjectOperation) Force(force bool) *MoveObjectOperation {
   225  	copy := *operation
   226  	copy.force = force
   227  	return &copy
   228  }
   229  
   230  func (operation *MoveObjectOperation) OnResponse(fn func()) *MoveObjectOperation {
   231  	copy := *operation
   232  	copy.onResponse = fn
   233  	return &copy
   234  }
   235  
   236  func (operation *MoveObjectOperation) OnError(fn func(error)) *MoveObjectOperation {
   237  	copy := *operation
   238  	copy.onError = fn
   239  	return &copy
   240  }
   241  
   242  func (operation *MoveObjectOperation) relatedEntries() []entry {
   243  	return []entry{{operation.fromObject.bucket.name, operation.fromObject.name}, operation.toObject}
   244  }
   245  
   246  func (operation *MoveObjectOperation) handleResponse(_ *ObjectDetails, err error) {
   247  	if err != nil && operation.onError != nil {
   248  		operation.onError(err)
   249  	} else if operation.onResponse != nil {
   250  		operation.onResponse()
   251  	}
   252  }
   253  
   254  func (operation *MoveObjectOperation) String() string {
   255  	s := "move/" + operation.fromObject.encode() + "/" + operation.toObject.encode()
   256  	if operation.force {
   257  		s += "/force/true"
   258  	}
   259  	return s
   260  }
   261  
   262  func (operation *MoveObjectOperation) Call(ctx context.Context) error {
   263  	_, err := operation.fromObject.bucket.objectsManager.storage.MoveObject(ctx, &apis.MoveObjectRequest{
   264  		SrcEntry:  operation.fromObject.String(),
   265  		DestEntry: operation.toObject.String(),
   266  		IsForce:   operation.force,
   267  	}, &apis.Options{
   268  		OverwrittenBucketName: operation.fromObject.bucket.name,
   269  	})
   270  	operation.handleResponse(nil, err)
   271  	return err
   272  }
   273  
   274  var _ Operation = (*MoveObjectOperation)(nil)
   275  
   276  func (operation *CopyObjectOperation) Force(force bool) *CopyObjectOperation {
   277  	copy := *operation
   278  	copy.force = force
   279  	return &copy
   280  }
   281  
   282  func (operation *CopyObjectOperation) OnResponse(fn func()) *CopyObjectOperation {
   283  	copy := *operation
   284  	copy.onResponse = fn
   285  	return &copy
   286  }
   287  
   288  func (operation *CopyObjectOperation) OnError(fn func(error)) *CopyObjectOperation {
   289  	copy := *operation
   290  	copy.onError = fn
   291  	return &copy
   292  }
   293  
   294  func (operation *CopyObjectOperation) relatedEntries() []entry {
   295  	return []entry{{operation.fromObject.bucket.name, operation.fromObject.name}, operation.toObject}
   296  }
   297  
   298  func (operation *CopyObjectOperation) handleResponse(_ *ObjectDetails, err error) {
   299  	if err != nil && operation.onError != nil {
   300  		operation.onError(err)
   301  	} else if operation.onResponse != nil {
   302  		operation.onResponse()
   303  	}
   304  }
   305  
   306  func (operation *CopyObjectOperation) String() string {
   307  	s := "copy/" + operation.fromObject.encode() + "/" + operation.toObject.encode()
   308  	if operation.force {
   309  		s += "/force/true"
   310  	}
   311  	return s
   312  }
   313  
   314  func (operation *CopyObjectOperation) Call(ctx context.Context) error {
   315  	_, err := operation.fromObject.bucket.objectsManager.storage.CopyObject(ctx, &apis.CopyObjectRequest{
   316  		SrcEntry:  operation.fromObject.String(),
   317  		DestEntry: operation.toObject.String(),
   318  		IsForce:   operation.force,
   319  	}, &apis.Options{
   320  		OverwrittenBucketName: operation.fromObject.bucket.name,
   321  	})
   322  	operation.handleResponse(nil, err)
   323  	return err
   324  }
   325  
   326  var _ Operation = (*CopyObjectOperation)(nil)
   327  
   328  func (operation *DeleteObjectOperation) OnResponse(fn func()) *DeleteObjectOperation {
   329  	copy := *operation
   330  	copy.onResponse = fn
   331  	return &copy
   332  }
   333  
   334  func (operation *DeleteObjectOperation) OnError(fn func(error)) *DeleteObjectOperation {
   335  	copy := *operation
   336  	copy.onError = fn
   337  	return &copy
   338  }
   339  
   340  func (operation *DeleteObjectOperation) handleResponse(_ *ObjectDetails, err error) {
   341  	if err != nil && operation.onError != nil {
   342  		operation.onError(err)
   343  	} else if operation.onResponse != nil {
   344  		operation.onResponse()
   345  	}
   346  }
   347  
   348  func (operation *DeleteObjectOperation) relatedEntries() []entry {
   349  	return []entry{{operation.object.bucket.name, operation.object.name}}
   350  }
   351  
   352  func (operation *DeleteObjectOperation) String() string {
   353  	return "delete/" + operation.object.encode()
   354  }
   355  
   356  func (operation *DeleteObjectOperation) Call(ctx context.Context) error {
   357  	_, err := operation.object.bucket.objectsManager.storage.DeleteObject(ctx, &apis.DeleteObjectRequest{
   358  		Entry: operation.object.String(),
   359  	}, &apis.Options{
   360  		OverwrittenBucketName: operation.object.bucket.name,
   361  	})
   362  	operation.handleResponse(nil, err)
   363  	return err
   364  }
   365  
   366  var _ Operation = (*DeleteObjectOperation)(nil)
   367  
   368  func (operation *RestoreObjectOperation) OnResponse(fn func()) *RestoreObjectOperation {
   369  	copy := *operation
   370  	copy.onResponse = fn
   371  	return &copy
   372  }
   373  
   374  func (operation *RestoreObjectOperation) OnError(fn func(error)) *RestoreObjectOperation {
   375  	copy := *operation
   376  	copy.onError = fn
   377  	return &copy
   378  }
   379  
   380  func (operation *RestoreObjectOperation) relatedEntries() []entry {
   381  	return []entry{{operation.object.bucket.name, operation.object.name}}
   382  }
   383  
   384  func (operation *RestoreObjectOperation) handleResponse(_ *ObjectDetails, err error) {
   385  	if err != nil && operation.onError != nil {
   386  		operation.onError(err)
   387  	} else if operation.onResponse != nil {
   388  		operation.onResponse()
   389  	}
   390  }
   391  
   392  func (operation *RestoreObjectOperation) String() string {
   393  	return "restoreAr/" + operation.object.encode() + "/freezeAfterDays/" + strconv.FormatInt(operation.freezeAfterDays, 10)
   394  }
   395  
   396  func (operation *RestoreObjectOperation) Call(ctx context.Context) error {
   397  	_, err := operation.object.bucket.objectsManager.storage.RestoreArchivedObject(ctx, &apis.RestoreArchivedObjectRequest{
   398  		Entry:           operation.object.String(),
   399  		FreezeAfterDays: int64(operation.freezeAfterDays),
   400  	}, &apis.Options{
   401  		OverwrittenBucketName: operation.object.bucket.name,
   402  	})
   403  	operation.handleResponse(nil, err)
   404  	return err
   405  }
   406  
   407  var _ Operation = (*RestoreObjectOperation)(nil)
   408  
   409  func (operation *SetObjectStorageClassOperation) OnResponse(fn func()) *SetObjectStorageClassOperation {
   410  	copy := *operation
   411  	copy.onResponse = fn
   412  	return &copy
   413  }
   414  
   415  func (operation *SetObjectStorageClassOperation) OnError(fn func(error)) *SetObjectStorageClassOperation {
   416  	copy := *operation
   417  	copy.onError = fn
   418  	return &copy
   419  }
   420  
   421  func (operation *SetObjectStorageClassOperation) relatedEntries() []entry {
   422  	return []entry{{operation.object.bucket.name, operation.object.name}}
   423  }
   424  
   425  func (operation *SetObjectStorageClassOperation) handleResponse(_ *ObjectDetails, err error) {
   426  	if err != nil && operation.onError != nil {
   427  		operation.onError(err)
   428  	} else if operation.onResponse != nil {
   429  		operation.onResponse()
   430  	}
   431  }
   432  
   433  func (operation *SetObjectStorageClassOperation) String() string {
   434  	return "chtype/" + operation.object.encode() + "/type/" + strconv.Itoa(int(operation.storageClass))
   435  }
   436  
   437  func (operation *SetObjectStorageClassOperation) Call(ctx context.Context) error {
   438  	_, err := operation.object.bucket.objectsManager.storage.SetObjectFileType(ctx, &apis.SetObjectFileTypeRequest{
   439  		Entry: operation.object.String(),
   440  		Type:  int64(operation.storageClass),
   441  	}, &apis.Options{
   442  		OverwrittenBucketName: operation.object.bucket.name,
   443  	})
   444  	operation.handleResponse(nil, err)
   445  	return err
   446  }
   447  
   448  var _ Operation = (*SetObjectStorageClassOperation)(nil)
   449  
   450  func (operation *SetObjectStatusOperation) OnResponse(fn func()) *SetObjectStatusOperation {
   451  	copy := *operation
   452  	copy.onResponse = fn
   453  	return &copy
   454  }
   455  
   456  func (operation *SetObjectStatusOperation) OnError(fn func(error)) *SetObjectStatusOperation {
   457  	copy := *operation
   458  	copy.onError = fn
   459  	return &copy
   460  }
   461  
   462  func (operation *SetObjectStatusOperation) relatedEntries() []entry {
   463  	return []entry{{operation.object.bucket.name, operation.object.name}}
   464  }
   465  
   466  func (operation *SetObjectStatusOperation) handleResponse(_ *ObjectDetails, err error) {
   467  	if err != nil && operation.onError != nil {
   468  		operation.onError(err)
   469  	} else if operation.onResponse != nil {
   470  		operation.onResponse()
   471  	}
   472  }
   473  
   474  func (operation *SetObjectStatusOperation) String() string {
   475  	return "chstatus/" + operation.object.encode() + "/status/" + strconv.Itoa(int(operation.status))
   476  }
   477  
   478  func (operation *SetObjectStatusOperation) Call(ctx context.Context) error {
   479  	_, err := operation.object.bucket.objectsManager.storage.ModifyObjectStatus(ctx, &apis.ModifyObjectStatusRequest{
   480  		Entry:  operation.object.String(),
   481  		Status: int64(operation.status),
   482  	}, &apis.Options{
   483  		OverwrittenBucketName: operation.object.bucket.name,
   484  	})
   485  	operation.handleResponse(nil, err)
   486  	return err
   487  }
   488  
   489  var _ Operation = (*SetObjectStatusOperation)(nil)
   490  
   491  func (operation *SetObjectMetadataOperation) Metadata(metadata map[string]string) *SetObjectMetadataOperation {
   492  	copy := *operation
   493  	copy.metadata = metadata
   494  	return &copy
   495  }
   496  
   497  func (operation *SetObjectMetadataOperation) Conditions(conds map[string]string) *SetObjectMetadataOperation {
   498  	copy := *operation
   499  	copy.conditions = conds
   500  	return &copy
   501  }
   502  
   503  func (operation *SetObjectMetadataOperation) OnResponse(fn func()) *SetObjectMetadataOperation {
   504  	copy := *operation
   505  	copy.onResponse = fn
   506  	return &copy
   507  }
   508  
   509  func (operation *SetObjectMetadataOperation) OnError(fn func(error)) *SetObjectMetadataOperation {
   510  	copy := *operation
   511  	copy.onError = fn
   512  	return &copy
   513  }
   514  
   515  func (operation *SetObjectMetadataOperation) relatedEntries() []entry {
   516  	return []entry{{operation.object.bucket.name, operation.object.name}}
   517  }
   518  
   519  func (operation *SetObjectMetadataOperation) handleResponse(_ *ObjectDetails, err error) {
   520  	if err != nil && operation.onError != nil {
   521  		operation.onError(err)
   522  	} else if operation.onResponse != nil {
   523  		operation.onResponse()
   524  	}
   525  }
   526  
   527  func (operation *SetObjectMetadataOperation) String() string {
   528  	s := "chgm/" + operation.object.encode() + "/mime/" + base64.URLEncoding.EncodeToString([]byte(operation.mimeType))
   529  	for k, v := range operation.metadata {
   530  		s += "/" + normalizeMetadataKey(k) + "/" + base64.URLEncoding.EncodeToString([]byte(v))
   531  	}
   532  	conds := []string{}
   533  	for k, v := range operation.conditions {
   534  		conds = append(conds, k+"="+v)
   535  	}
   536  	if len(conds) > 0 {
   537  		s += "/cond/" + base64.URLEncoding.EncodeToString([]byte(strings.Join(conds, "&")))
   538  	}
   539  	return s
   540  }
   541  
   542  func (operation *SetObjectMetadataOperation) Call(ctx context.Context) error {
   543  	conds := make([]string, 0, len(operation.conditions))
   544  	for k, v := range operation.conditions {
   545  		conds = append(conds, k+"="+v)
   546  	}
   547  	metadata := make(map[string]string, len(operation.metadata))
   548  	for k, v := range operation.metadata {
   549  		metadata[normalizeMetadataKey(k)] = v
   550  	}
   551  	_, err := operation.object.bucket.objectsManager.storage.ModifyObjectMetadata(ctx, &apis.ModifyObjectMetadataRequest{
   552  		Entry:     operation.object.String(),
   553  		MimeType:  operation.mimeType,
   554  		Condition: strings.Join(conds, "&"),
   555  		MetaData:  metadata,
   556  	}, &apis.Options{
   557  		OverwrittenBucketName: operation.object.bucket.name,
   558  	})
   559  	operation.handleResponse(nil, err)
   560  	return err
   561  }
   562  
   563  var _ Operation = (*SetObjectMetadataOperation)(nil)
   564  
   565  func (operation *SetObjectLifeCycleOperation) ToIAAfterDays(afterDays int64) *SetObjectLifeCycleOperation {
   566  	operation.toIAAfterDays = afterDays
   567  	return operation
   568  }
   569  
   570  func (operation *SetObjectLifeCycleOperation) ToArchiveIRAfterDays(afterDays int64) *SetObjectLifeCycleOperation {
   571  	copy := *operation
   572  	copy.toArchiveIRAfterDays = afterDays
   573  	return &copy
   574  }
   575  
   576  func (operation *SetObjectLifeCycleOperation) ToArchiveAfterDays(afterDays int64) *SetObjectLifeCycleOperation {
   577  	copy := *operation
   578  	copy.toArchiveAfterDays = afterDays
   579  	return &copy
   580  }
   581  
   582  func (operation *SetObjectLifeCycleOperation) ToDeepArchiveAfterDays(afterDays int64) *SetObjectLifeCycleOperation {
   583  	copy := *operation
   584  	copy.toDeepArchiveAfterDays = afterDays
   585  	return &copy
   586  }
   587  
   588  func (operation *SetObjectLifeCycleOperation) DeleteAfterDays(afterDays int64) *SetObjectLifeCycleOperation {
   589  	copy := *operation
   590  	copy.deleteAfterDays = afterDays
   591  	return &copy
   592  }
   593  
   594  func (operation *SetObjectLifeCycleOperation) OnResponse(fn func()) *SetObjectLifeCycleOperation {
   595  	copy := *operation
   596  	copy.onResponse = fn
   597  	return &copy
   598  }
   599  
   600  func (operation *SetObjectLifeCycleOperation) OnError(fn func(error)) *SetObjectLifeCycleOperation {
   601  	copy := *operation
   602  	copy.onError = fn
   603  	return &copy
   604  }
   605  
   606  func (operation *SetObjectLifeCycleOperation) relatedEntries() []entry {
   607  	return []entry{{operation.object.bucket.name, operation.object.name}}
   608  }
   609  
   610  func (operation *SetObjectLifeCycleOperation) handleResponse(_ *ObjectDetails, err error) {
   611  	if err != nil && operation.onError != nil {
   612  		operation.onError(err)
   613  	} else if operation.onResponse != nil {
   614  		operation.onResponse()
   615  	}
   616  }
   617  
   618  func (operation *SetObjectLifeCycleOperation) String() string {
   619  	s := "lifecycle/" + operation.object.encode()
   620  	if operation.toIAAfterDays > 0 {
   621  		s += "/toIAAfterDays/" + strconv.FormatInt(operation.toIAAfterDays, 10)
   622  	}
   623  	if operation.toArchiveIRAfterDays > 0 {
   624  		s += "/toArchiveIRAfterDays/" + strconv.FormatInt(operation.toArchiveIRAfterDays, 10)
   625  	}
   626  	if operation.toArchiveAfterDays > 0 {
   627  		s += "/toArchiveAfterDays/" + strconv.FormatInt(operation.toArchiveAfterDays, 10)
   628  	}
   629  	if operation.toDeepArchiveAfterDays > 0 {
   630  		s += "/toDeepArchiveAfterDays/" + strconv.FormatInt(operation.toDeepArchiveAfterDays, 10)
   631  	}
   632  	if operation.deleteAfterDays > 0 {
   633  		s += "/deleteAfterDays/" + strconv.FormatInt(operation.deleteAfterDays, 10)
   634  	}
   635  	return s
   636  }
   637  
   638  func (operation *SetObjectLifeCycleOperation) Call(ctx context.Context) error {
   639  	_, err := operation.object.bucket.objectsManager.storage.ModifyObjectLifeCycle(ctx, &apis.ModifyObjectLifeCycleRequest{
   640  		Entry:                  operation.object.String(),
   641  		ToIaAfterDays:          operation.toIAAfterDays,
   642  		ToArchiveAfterDays:     operation.toArchiveAfterDays,
   643  		ToDeepArchiveAfterDays: operation.toDeepArchiveAfterDays,
   644  		ToArchiveIrAfterDays:   operation.toArchiveIRAfterDays,
   645  		DeleteAfterDays:        operation.deleteAfterDays,
   646  	}, &apis.Options{
   647  		OverwrittenBucketName: operation.object.bucket.name,
   648  	})
   649  	operation.handleResponse(nil, err)
   650  	return err
   651  }
   652  
   653  var _ Operation = (*SetObjectLifeCycleOperation)(nil)
   654  
   655  func (entry Object) String() string {
   656  	return entry.bucket.name + ":" + entry.name
   657  }
   658  
   659  func (entry Object) encode() string {
   660  	return base64.URLEncoding.EncodeToString([]byte(entry.String()))
   661  }
   662  
   663  func (entry entry) String() string {
   664  	return entry.bucketName + ":" + entry.objectName
   665  }
   666  
   667  func (entry entry) encode() string {
   668  	return base64.URLEncoding.EncodeToString([]byte(entry.String()))
   669  }
   670  
   671  func normalizeMetadataKey(k string) string {
   672  	if !strings.HasPrefix(k, "x-qn-meta-") {
   673  		k = "x-qn-meta-" + k
   674  	}
   675  	return k
   676  }