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

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/qiniu/go-sdk/v7/auth"
    10  	"github.com/qiniu/go-sdk/v7/internal/clientv2"
    11  	"github.com/qiniu/go-sdk/v7/storagev2/apis"
    12  	"github.com/qiniu/go-sdk/v7/storagev2/defaults"
    13  	"github.com/qiniu/go-sdk/v7/storagev2/http_client"
    14  	region_v2 "github.com/qiniu/go-sdk/v7/storagev2/region"
    15  )
    16  
    17  // 存储所在的地区,例如华东,华南,华北
    18  // 每个存储区域可能有多个机房信息,每个机房可能有多个上传入口
    19  type Region struct {
    20  	// 上传入口
    21  	SrcUpHosts []string `json:"src_up,omitempty"`
    22  
    23  	// 加速上传入口
    24  	CdnUpHosts []string `json:"cdn_up,omitempty"`
    25  
    26  	// 获取文件信息入口
    27  	RsHost string `json:"rs,omitempty"`
    28  
    29  	// bucket列举入口
    30  	RsfHost string `json:"rsf,omitempty"`
    31  
    32  	ApiHost string `json:"api,omitempty"`
    33  
    34  	// 存储io 入口
    35  	IovipHost string `json:"io,omitempty"`
    36  
    37  	// 源站下载入口
    38  	IoSrcHost string `json:"io_src,omitempty"`
    39  }
    40  
    41  type RegionID string
    42  
    43  // GetDefaultReion 根据RegionID获取对应的Region信息
    44  func GetRegionByID(regionID RegionID) (Region, bool) {
    45  	if r, ok := regionMap[regionID]; ok {
    46  		return r, ok
    47  	}
    48  	return Region{}, false
    49  }
    50  
    51  func (r *Region) String() string {
    52  	str := ""
    53  	str += fmt.Sprintf("SrcUpHosts: %v\n", r.SrcUpHosts)
    54  	str += fmt.Sprintf("CdnUpHosts: %v\n", r.CdnUpHosts)
    55  	str += fmt.Sprintf("IovipHost: %s\n", r.IovipHost)
    56  	str += fmt.Sprintf("RsHost: %s\n", r.RsHost)
    57  	str += fmt.Sprintf("RsfHost: %s\n", r.RsfHost)
    58  	str += fmt.Sprintf("ApiHost: %s\n", r.ApiHost)
    59  	return str
    60  }
    61  
    62  func endpoint(useHttps bool, host string) string {
    63  	host = strings.TrimSpace(host)
    64  	if host == "" {
    65  		return ""
    66  	}
    67  
    68  	if strings.HasPrefix(host, "http://") ||
    69  		strings.HasPrefix(host, "https://") {
    70  		return host
    71  	}
    72  
    73  	scheme := "http://"
    74  	if useHttps {
    75  		scheme = "https://"
    76  	}
    77  	return fmt.Sprintf("%s%s", scheme, host)
    78  }
    79  
    80  // 获取rsfHost
    81  func (r *Region) GetRsfHost(useHttps bool) string {
    82  	return endpoint(useHttps, r.RsfHost)
    83  }
    84  
    85  // 获取io host
    86  func (r *Region) GetIoHost(useHttps bool) string {
    87  	return endpoint(useHttps, r.IovipHost)
    88  }
    89  
    90  // 获取RsHost
    91  func (r *Region) GetRsHost(useHttps bool) string {
    92  	return endpoint(useHttps, r.RsHost)
    93  }
    94  
    95  // 获取api host
    96  func (r *Region) GetApiHost(useHttps bool) string {
    97  	return endpoint(useHttps, r.ApiHost)
    98  }
    99  
   100  func (r *Region) GetRegions(ctx context.Context) ([]*region_v2.Region, error) {
   101  	newRegion := &region_v2.Region{
   102  		Up: region_v2.Endpoints{Preferred: append(r.CdnUpHosts, r.SrcUpHosts...)},
   103  	}
   104  	if host := r.IovipHost; host != "" {
   105  		newRegion.Io = region_v2.Endpoints{Preferred: []string{host}}
   106  	}
   107  	if host := r.IoSrcHost; host != "" {
   108  		newRegion.IoSrc = region_v2.Endpoints{Preferred: []string{host}}
   109  	}
   110  	if host := r.RsHost; host != "" {
   111  		newRegion.Rs = region_v2.Endpoints{Preferred: []string{host}}
   112  	}
   113  	if host := r.RsfHost; host != "" {
   114  		newRegion.Rsf = region_v2.Endpoints{Preferred: []string{host}}
   115  	}
   116  	if host := r.ApiHost; host != "" {
   117  		newRegion.Api = region_v2.Endpoints{Preferred: []string{host}}
   118  	}
   119  	// 此包需要使用 ucHosts 作为 v2 包中的 uc 域名
   120  	// ucHosts 用户可通过 SetUcHosts 自定义
   121  	newRegion.Bucket = region_v2.Endpoints{Preferred: getUCHosts()}
   122  	return []*region_v2.Region{newRegion}, nil
   123  }
   124  
   125  var (
   126  	// regionHuadong 表示华东机房
   127  	regionHuadong = Region{
   128  		SrcUpHosts: []string{
   129  			"up.qiniup.com",
   130  		},
   131  		CdnUpHosts: []string{
   132  			"upload.qiniup.com",
   133  		},
   134  		RsHost:    "rs.qbox.me",
   135  		RsfHost:   "rsf.qbox.me",
   136  		ApiHost:   "api.qiniu.com",
   137  		IovipHost: "iovip.qbox.me",
   138  	}
   139  
   140  	// regionHuadongZhejiang2 表示华东-浙江2
   141  	regionHuadongZhejiang2 = Region{
   142  		SrcUpHosts: []string{
   143  			"up-cn-east-2.qiniup.com",
   144  		},
   145  		CdnUpHosts: []string{
   146  			"upload-cn-east-2.qiniup.com",
   147  		},
   148  		RsHost:    "rs-cn-east-2.qiniuapi.com",
   149  		RsfHost:   "rsf-cn-east-2.qiniuapi.com",
   150  		ApiHost:   "api-cn-east-2.qiniuapi.com",
   151  		IovipHost: "iovip-cn-east-2.qiniuio.com",
   152  	}
   153  
   154  	// regionHuabei 表示华北机房
   155  	regionHuabei = Region{
   156  		SrcUpHosts: []string{
   157  			"up-z1.qiniup.com",
   158  		},
   159  		CdnUpHosts: []string{
   160  			"upload-z1.qiniup.com",
   161  		},
   162  		RsHost:    "rs-z1.qbox.me",
   163  		RsfHost:   "rsf-z1.qbox.me",
   164  		ApiHost:   "api-z1.qiniuapi.com",
   165  		IovipHost: "iovip-z1.qbox.me",
   166  	}
   167  
   168  	// regionHuanan 表示华南机房
   169  	regionHuanan = Region{
   170  		SrcUpHosts: []string{
   171  			"up-z2.qiniup.com",
   172  		},
   173  		CdnUpHosts: []string{
   174  			"upload-z2.qiniup.com",
   175  		},
   176  		RsHost:    "rs-z2.qbox.me",
   177  		RsfHost:   "rsf-z2.qbox.me",
   178  		ApiHost:   "api-z2.qiniuapi.com",
   179  		IovipHost: "iovip-z2.qbox.me",
   180  	}
   181  
   182  	// regionNorthAmerica 表示北美机房
   183  	regionNorthAmerica = Region{
   184  		SrcUpHosts: []string{
   185  			"up-na0.qiniup.com",
   186  		},
   187  		CdnUpHosts: []string{
   188  			"upload-na0.qiniup.com",
   189  		},
   190  		RsHost:    "rs-na0.qbox.me",
   191  		RsfHost:   "rsf-na0.qbox.me",
   192  		ApiHost:   "api-na0.qiniuapi.com",
   193  		IovipHost: "iovip-na0.qbox.me",
   194  	}
   195  
   196  	// regionSingapore 表示新加坡机房
   197  	regionSingapore = Region{
   198  		SrcUpHosts: []string{
   199  			"up-as0.qiniup.com",
   200  		},
   201  		CdnUpHosts: []string{
   202  			"upload-as0.qiniup.com",
   203  		},
   204  		RsHost:    "rs-as0.qbox.me",
   205  		RsfHost:   "rsf-as0.qbox.me",
   206  		ApiHost:   "api-as0.qiniuapi.com",
   207  		IovipHost: "iovip-as0.qbox.me",
   208  	}
   209  )
   210  
   211  const (
   212  	// region code
   213  	RIDHuadong          = RegionID("z0")
   214  	RIDHuadongZheJiang2 = RegionID("cn-east-2")
   215  	RIDHuabei           = RegionID("z1")
   216  	RIDHuanan           = RegionID("z2")
   217  	RIDNorthAmerica     = RegionID("na0")
   218  	RIDSingapore        = RegionID("as0")
   219  )
   220  
   221  // regionMap 是RegionID到具体的Region的映射
   222  var regionMap = map[RegionID]Region{
   223  	RIDHuadong:          regionHuadong,
   224  	RIDHuadongZheJiang2: regionHuadongZhejiang2,
   225  	RIDHuanan:           regionHuanan,
   226  	RIDHuabei:           regionHuabei,
   227  	RIDSingapore:        regionSingapore,
   228  	RIDNorthAmerica:     regionNorthAmerica,
   229  }
   230  
   231  const (
   232  	defaultUcHost0 = "uc.qiniuapi.com"
   233  	defaultUcHost1 = "kodo-config.qiniuapi.com"
   234  	defaultUcHost2 = "uc.qbox.me"
   235  )
   236  
   237  // UcHost 为查询空间相关域名的 API 服务地址
   238  // 设置 UcHost 时,如果不指定 scheme 默认会使用 https
   239  // Deprecated 使用 SetUcHosts 替换
   240  var UcHost = ""
   241  
   242  var (
   243  	ucHostsLock sync.RWMutex
   244  	ucHosts     = []string{defaultUcHost0, defaultUcHost1, defaultUcHost2}
   245  )
   246  
   247  func init() {
   248  	if defaultUcHosts, err := defaults.BucketURLs(); err == nil && len(defaultUcHosts) > 0 {
   249  		SetUcHosts(defaultUcHosts...)
   250  	}
   251  }
   252  
   253  // SetUcHost
   254  // Deprecated 使用 SetUcHosts 替换
   255  func SetUcHost(host string, useHttps bool) {
   256  	if len(host) == 0 {
   257  		return
   258  	}
   259  	host = endpoint(useHttps, host)
   260  	SetUcHosts(host)
   261  }
   262  
   263  // SetUcHosts 配置多个 UC 域名
   264  func SetUcHosts(hosts ...string) {
   265  	var newHosts []string
   266  	for _, host := range hosts {
   267  		if len(host) > 0 {
   268  			newHosts = append(newHosts, host)
   269  		}
   270  	}
   271  
   272  	ucHostsLock.Lock()
   273  	defer ucHostsLock.Unlock()
   274  	ucHosts = newHosts
   275  }
   276  
   277  func getUCHosts() []string {
   278  	ucHostsLock.RLock()
   279  	defer ucHostsLock.RUnlock()
   280  
   281  	hosts := make([]string, 0, len(ucHosts))
   282  	for _, host := range ucHosts {
   283  		if len(host) > 0 {
   284  			hosts = append(hosts, host)
   285  		}
   286  	}
   287  	return hosts
   288  }
   289  
   290  func getUcEndpointProvider(useHttps bool, hosts []string) region_v2.EndpointsProvider {
   291  	if len(hosts) == 0 {
   292  		if len(UcHost) > 0 {
   293  			hosts = append(hosts, endpoint(useHttps, UcHost))
   294  		}
   295  
   296  		oldHosts := getUCHosts()
   297  		for _, host := range oldHosts {
   298  			hosts = append(hosts, endpoint(useHttps, host))
   299  		}
   300  	}
   301  
   302  	if len(hosts) > 0 {
   303  		return region_v2.Endpoints{Preferred: hosts}
   304  	} else {
   305  		return nil
   306  	}
   307  }
   308  
   309  func getUcEndpoint(useHttps bool, hosts []string) region_v2.Endpoints {
   310  	provider := getUcEndpointProvider(useHttps, hosts)
   311  	if provider == nil {
   312  		return region_v2.Endpoints{}
   313  	}
   314  
   315  	if p, ok := provider.(region_v2.Endpoints); ok {
   316  		return p
   317  	} else {
   318  		return region_v2.Endpoints{}
   319  	}
   320  }
   321  
   322  // GetRegion 用来根据ak和bucket来获取空间相关的机房信息
   323  // 延用 v2, v2 结构和 v4 结构不同且暂不可替代
   324  // Deprecated 使用 GetRegionWithOptions 替换
   325  func GetRegion(ak, bucket string) (*Region, error) {
   326  	return GetRegionWithOptions(ak, bucket, DefaultUCApiOptions())
   327  }
   328  
   329  // GetRegionWithOptions 用来根据ak和bucket来获取空间相关的机房信息
   330  func GetRegionWithOptions(ak, bucket string, options UCApiOptions) (*Region, error) {
   331  	return getRegionByV2(ak, bucket, options)
   332  }
   333  
   334  // 使用 v4
   335  //
   336  //lint:ignore U1000 Used by test case
   337  func getRegionGroup(ak, bucket string) (*RegionGroup, error) {
   338  	return getRegionByV4(ak, bucket, DefaultUCApiOptions())
   339  }
   340  
   341  func getRegionGroupWithOptions(ak, bucket string, options UCApiOptions) (*RegionGroup, error) {
   342  	return getRegionByV4(ak, bucket, options)
   343  }
   344  
   345  type RegionInfo struct {
   346  	ID          string `json:"id"`
   347  	Description string `json:"description"`
   348  }
   349  
   350  func SetRegionCachePath(newPath string) {
   351  	setRegionV2CachePath(newPath)
   352  	setRegionV4CachePath(newPath)
   353  }
   354  
   355  // GetRegionsInfo Deprecated and use GetRegionsInfoWithOptions instead
   356  // Deprecated
   357  func GetRegionsInfo(mac *auth.Credentials) ([]RegionInfo, error) {
   358  	return GetRegionsInfoWithOptions(mac, DefaultUCApiOptions())
   359  }
   360  
   361  func GetRegionsInfoWithOptions(mac *auth.Credentials, options UCApiOptions) ([]RegionInfo, error) {
   362  	var httpClient clientv2.Client
   363  	if options.Client != nil {
   364  		httpClient = options.Client.Client
   365  	}
   366  
   367  	if mac == nil {
   368  		mac = auth.Default()
   369  	}
   370  
   371  	response, err := apis.NewStorage(&http_client.Options{
   372  		BasicHTTPClient:    httpClient,
   373  		HostFreezeDuration: options.HostFreezeDuration,
   374  		HostRetryConfig: &clientv2.RetryConfig{
   375  			RetryMax: options.RetryMax,
   376  		},
   377  	}).GetRegions(
   378  		context.Background(),
   379  		&apis.GetRegionsRequest{Credentials: mac},
   380  		&apis.Options{OverwrittenBucketHosts: getUcEndpointProvider(options.UseHttps, options.Hosts)},
   381  	)
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  
   386  	regions := make([]RegionInfo, 0, len(response.Regions))
   387  	for _, region := range response.Regions {
   388  		regions = append(regions, RegionInfo{
   389  			ID:          region.Id,
   390  			Description: region.Description,
   391  		})
   392  	}
   393  	return regions, nil
   394  }