github.com/qiniu/go-sdk/v7@v7.27.0/storage/util.go (about)

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"time"
     7  
     8  	api "github.com/qiniu/go-sdk/v7"
     9  	"github.com/qiniu/go-sdk/v7/internal/hostprovider"
    10  	"github.com/qiniu/go-sdk/v7/storagev2/retrier"
    11  )
    12  
    13  func parseEtag(etag string) string {
    14  	etag = strings.TrimPrefix(etag, "\"")
    15  	etag = strings.TrimSuffix(etag, "\"")
    16  	etag = strings.TrimSuffix(etag, ".gz")
    17  	return etag
    18  }
    19  
    20  // ParsePutTime 提供了将PutTime转换为 time.Time 的功能
    21  func ParsePutTime(putTime int64) (t time.Time) {
    22  	t = time.Unix(0, putTime*100)
    23  	return
    24  }
    25  
    26  // IsContextExpired 检查分片上传的ctx是否过期,提前一天让它过期
    27  // 因为我们认为如果断点继续上传的话,最长需要1天时间
    28  func IsContextExpired(blkPut BlkputRet) bool {
    29  	if blkPut.Ctx == "" {
    30  		return false
    31  	}
    32  	target := time.Unix(blkPut.ExpiredAt, 0).AddDate(0, 0, -1)
    33  	now := time.Now()
    34  	return now.After(target)
    35  }
    36  
    37  func isUploadContextExpired(expiredAt int64) bool {
    38  	target := time.Unix(expiredAt, 0).Add(-2 * time.Hour)
    39  	return time.Now().After(target)
    40  }
    41  
    42  func shouldUploadAgain(err error) bool {
    43  	if err == nil {
    44  		return false
    45  	}
    46  
    47  	if isCancelErr(err) {
    48  		return false
    49  	}
    50  
    51  	switch t := err.(type) {
    52  	case *ErrorInfo:
    53  		// 4xx 不重试
    54  		return t.Code < 400 || t.Code > 499
    55  	case *api.QError:
    56  		return t.Code == ErrMaxUpRetry
    57  	default:
    58  		// 网络异常可重试
    59  		return shouldUploadRetryWithOtherHost(err)
    60  	}
    61  }
    62  
    63  func isContextExpiredError(err error) bool {
    64  	if err == nil {
    65  		return false
    66  	}
    67  
    68  	errInfo, ok := err.(*ErrorInfo)
    69  	if !ok {
    70  		return false
    71  	}
    72  
    73  	return errInfo.Code == 701 || (errInfo.Code == 612 && strings.Contains(errInfo.Error(), "no such uploadId"))
    74  }
    75  
    76  func shouldUploadRetryWithOtherHost(err error) bool {
    77  	return retrier.IsErrorRetryable(err)
    78  }
    79  
    80  func doUploadAction(hostProvider hostprovider.HostProvider, retryMax int, freezeDuration time.Duration, action func(host string) error) error {
    81  	for {
    82  		host, err := hostProvider.Provider()
    83  		if err != nil {
    84  			return api.NewError(ErrMaxUpRetry, err.Error())
    85  		}
    86  
    87  		for i := 0; ; i++ {
    88  			err = action(host)
    89  
    90  			// 请求成功
    91  			if err == nil {
    92  				return nil
    93  			}
    94  
    95  			// 不可重试错误
    96  			if !shouldUploadRetryWithOtherHost(err) {
    97  				return err
    98  			}
    99  
   100  			// 超过重试次数退出
   101  			if i >= retryMax {
   102  				break
   103  			}
   104  		}
   105  
   106  		// 单个 host 失败,冻结此 host,换其他 host
   107  		_ = hostProvider.Freeze(host, err, freezeDuration)
   108  	}
   109  }
   110  
   111  func isCancelErr(err error) bool {
   112  	if err == context.Canceled {
   113  		return true
   114  	}
   115  
   116  	if err == nil {
   117  		return false
   118  	}
   119  
   120  	return strings.Contains(err.Error(), "context canceled")
   121  }