github.com/qiniu/go-sdk/v7@v7.27.0/storagev2/region/all.go (about) 1 package region 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 "net" 8 "net/http" 9 "os" 10 "path/filepath" 11 "time" 12 13 "github.com/qiniu/go-sdk/v7/internal/cache" 14 "github.com/qiniu/go-sdk/v7/internal/clientv2" 15 "github.com/qiniu/go-sdk/v7/storagev2/backoff" 16 "github.com/qiniu/go-sdk/v7/storagev2/chooser" 17 "github.com/qiniu/go-sdk/v7/storagev2/credentials" 18 "github.com/qiniu/go-sdk/v7/storagev2/resolver" 19 "github.com/qiniu/go-sdk/v7/storagev2/retrier" 20 ) 21 22 type ( 23 allRegionsProvider struct { 24 credentials credentials.CredentialsProvider 25 bucketHosts Endpoints 26 cache *cache.Cache 27 client clientv2.Client 28 useHttps bool 29 } 30 31 // AllRegionsProviderOptions 所有区域提供者选项 32 AllRegionsProviderOptions struct { 33 // 使用 HTTP 协议 34 UseInsecureProtocol bool 35 36 // 压缩周期(默认:60s) 37 CompactInterval time.Duration 38 39 // 持久化路径(默认:$TMPDIR/qiniu-golang-sdk/regions_v4_01.cache.json) 40 PersistentFilePath string 41 42 // 持久化周期(默认:60s) 43 PersistentDuration time.Duration 44 45 // 单域名重试次数(默认:2) 46 RetryMax int 47 48 // 主备域名冻结时间(默认:600s),当一个域名请求失败(单个域名会被重试 RetryMax 次),会被冻结一段时间,使用备用域名进行重试,在冻结时间内,域名不能被使用,当一个操作中所有域名竣备冻结操作不在进行重试,返回最后一次操作的错误。 49 HostFreezeDuration time.Duration 50 51 // HTTP 客户端,如果不配置则使用默认的 HTTP 客户端 52 Client clientv2.Client 53 54 // 域名解析器,如果不配置则使用默认的域名解析器 55 Resolver resolver.Resolver 56 57 // 域名选择器,如果不配置则使用默认的域名选择器 58 Chooser chooser.Chooser 59 60 // 退避器,如果不配置则使用默认的退避器 61 Backoff backoff.Backoff 62 63 // 签名前回调函数 64 BeforeSign func(*http.Request) 65 66 // 签名后回调函数 67 AfterSign func(*http.Request) 68 69 // 签名错误回调函数 70 SignError func(*http.Request, error) 71 72 // 域名解析前回调函数 73 BeforeResolve func(*http.Request) 74 75 // 域名解析后回调函数 76 AfterResolve func(*http.Request, []net.IP) 77 78 // 域名解析错误回调函数 79 ResolveError func(*http.Request, error) 80 81 // 退避前回调函数 82 BeforeBackoff func(*http.Request, *retrier.RetrierOptions, time.Duration) 83 84 // 退避后回调函数 85 AfterBackoff func(*http.Request, *retrier.RetrierOptions, time.Duration) 86 87 // 请求前回调函数 88 BeforeRequest func(*http.Request, *retrier.RetrierOptions) 89 90 // 请求后回调函数 91 AfterResponse func(*http.Response, *retrier.RetrierOptions, error) 92 } 93 94 singleRegion struct { 95 ID string `json:"id"` 96 Ttl int64 `json:"ttl"` 97 Io v4QueryServiceHosts `json:"io"` 98 Up v4QueryServiceHosts `json:"up"` 99 Rs v4QueryServiceHosts `json:"rs"` 100 Rsf v4QueryServiceHosts `json:"rsf"` 101 Api v4QueryServiceHosts `json:"api"` 102 Uc v4QueryServiceHosts `json:"uc"` 103 } 104 105 regionsResponse struct { 106 Regions []singleRegion `json:"regions"` 107 } 108 ) 109 110 const allRegionsProviderCacheFileName = "regions_v4_01.cache.json" 111 112 // NewAllRegionsProvider 创建所有空间提供者 113 func NewAllRegionsProvider(credentials credentials.CredentialsProvider, bucketHosts Endpoints, opts *AllRegionsProviderOptions) (RegionsProvider, error) { 114 if opts == nil { 115 opts = &AllRegionsProviderOptions{} 116 } 117 retryMax := opts.RetryMax 118 if retryMax <= 0 { 119 retryMax = 2 120 } 121 compactInterval := opts.CompactInterval 122 if compactInterval == time.Duration(0) { 123 compactInterval = time.Minute 124 } 125 persistentFilePath := opts.PersistentFilePath 126 if persistentFilePath == "" { 127 persistentFilePath = filepath.Join(os.TempDir(), "qiniu-golang-sdk", allRegionsProviderCacheFileName) 128 } 129 persistentDuration := opts.PersistentDuration 130 if persistentDuration == time.Duration(0) { 131 persistentDuration = time.Minute 132 } 133 134 persistentCache, err := getPersistentCache(persistentFilePath, compactInterval, persistentDuration) 135 if err != nil { 136 return nil, err 137 } 138 139 return &allRegionsProvider{ 140 credentials: credentials, 141 bucketHosts: bucketHosts, 142 cache: persistentCache, 143 client: makeBucketQueryClient( 144 opts.Client, 145 credentials, 146 bucketHosts, 147 !opts.UseInsecureProtocol, 148 retryMax, 149 opts.HostFreezeDuration, 150 opts.Resolver, 151 opts.Chooser, 152 opts.Backoff, 153 opts.BeforeResolve, 154 opts.AfterResolve, 155 opts.ResolveError, 156 opts.BeforeBackoff, 157 opts.AfterBackoff, 158 opts.BeforeRequest, 159 opts.AfterResponse, 160 opts.BeforeSign, 161 opts.AfterSign, 162 opts.SignError, 163 ), 164 useHttps: !opts.UseInsecureProtocol, 165 }, nil 166 } 167 168 func (provider *allRegionsProvider) GetRegions(ctx context.Context) ([]*Region, error) { 169 creds, err := provider.credentials.Get(ctx) 170 if err != nil { 171 return nil, err 172 } 173 cacheValue, status := provider.cache.Get(makeRegionsProviderCacheKey(creds.AccessKey, provider.bucketHosts), func() (cache.CacheValue, error) { 174 var ret regionsResponse 175 url := provider.bucketHosts.firstUrl(provider.useHttps) + "/regions" 176 if err = clientv2.DoAndDecodeJsonResponse(provider.client, clientv2.RequestParams{ 177 Context: ctx, 178 Method: clientv2.RequestMethodGet, 179 Url: url, 180 BufferResponse: true, 181 }, &ret); err != nil { 182 return nil, err 183 } 184 return ret.toCacheValue(), nil 185 }) 186 if status == cache.NoResultGot { 187 return nil, err 188 } 189 return cacheValue.(*v4QueryCacheValue).Regions, nil 190 } 191 192 func (response *regionsResponse) toCacheValue() *v4QueryCacheValue { 193 var ( 194 minTtl = int64(math.MaxInt64) 195 regions = make([]*Region, 0, len(response.Regions)) 196 ) 197 for _, host := range response.Regions { 198 regions = append(regions, host.toCacheValue()) 199 if host.Ttl < minTtl { 200 minTtl = host.Ttl 201 } 202 } 203 now := time.Now() 204 return &v4QueryCacheValue{ 205 Regions: regions, 206 RefreshAfter: now.Add(time.Duration(minTtl/2) * time.Second), 207 ExpiredAt: now.Add(time.Duration(minTtl) * time.Second), 208 } 209 } 210 211 func (response *singleRegion) toCacheValue() *Region { 212 return &Region{ 213 RegionID: response.ID, 214 Up: response.Up.toCacheValue(), 215 Io: response.Io.toCacheValue(), 216 Rs: response.Rs.toCacheValue(), 217 Rsf: response.Rsf.toCacheValue(), 218 Api: response.Api.toCacheValue(), 219 Bucket: response.Uc.toCacheValue(), 220 } 221 } 222 223 func makeRegionsProviderCacheKey(accessKey string, bucketHosts Endpoints) string { 224 return fmt.Sprintf("%s:%s", accessKey, makeBucketHostsCacheKey(bucketHosts)) 225 }