github.com/qiniu/go-sdk/v7@v7.27.0/cdn/api.go (about)

     1  package cdn
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"strings"
    11  
    12  	"github.com/qiniu/go-sdk/v7/auth"
    13  )
    14  
    15  // Fusion CDN服务域名
    16  var (
    17  	FusionHost = "http://fusion.qiniuapi.com"
    18  )
    19  
    20  // CdnManager 提供了文件和目录刷新,文件预取,获取域名带宽和流量数据,获取域名日志列表等功能
    21  type CdnManager struct {
    22  	mac *auth.Credentials
    23  }
    24  
    25  // NewCdnManager 用来构建一个新的 CdnManager
    26  func NewCdnManager(mac *auth.Credentials) *CdnManager {
    27  	if mac == nil {
    28  		mac = auth.Default()
    29  	}
    30  	return &CdnManager{mac: mac}
    31  }
    32  
    33  // TrafficReq 为批量查询带宽/流量的API请求内容
    34  //
    35  //	StartDate 	开始日期,格式例如:2016-07-01
    36  //	EndDate 	结束日期,格式例如:2016-07-03
    37  //	Granularity	取值粒度,取值可选值:5min/hour/day
    38  //	Domains 	域名列表,彼此用 ; 连接
    39  //	DataType        计量数据类型, 可选 'bandwidth'(静态cdn带宽,默认)..., 参考 [DataType]
    40  type TrafficReq struct {
    41  	StartDate   string `json:"startDate"`
    42  	EndDate     string `json:"endDate"`
    43  	Granularity string `json:"granularity"`
    44  	Domains     string `json:"domains"`
    45  	DataType    string `json:"type,omitempty"`
    46  }
    47  
    48  // TrafficResp 为带宽/流量查询响应内容
    49  type TrafficResp struct {
    50  	Code  int                    `json:"code"`
    51  	Error string                 `json:"error"`
    52  	Time  []string               `json:"time,omitempty"`
    53  	Data  map[string]TrafficData `json:"data,omitempty"`
    54  }
    55  
    56  // TrafficData 为带宽/流量数据
    57  type TrafficData struct {
    58  	DomainChina   []int `json:"china"`
    59  	DomainOversea []int `json:"oversea"`
    60  }
    61  
    62  type options struct {
    63  	dataType DataType
    64  }
    65  
    66  func _WithDataType(dataType DataType) Option {
    67  	return OptionFunc(func(opt interface{}) {
    68  		opt.(*options).dataType = dataType
    69  	})
    70  }
    71  
    72  type BandwidthOption Option
    73  
    74  func WithBandwidthDataType(dataType DataType) BandwidthOption {
    75  	if DataTypeBandwidth <= dataType && dataType <= DataType302mBandwidth {
    76  		return _WithDataType(dataType)
    77  	}
    78  	panic("cdn: invalid DataType for GetBandwidthData: " + dataType.String())
    79  }
    80  
    81  // GetBandwidthData 方法用来获取域名访问带宽数据
    82  //
    83  //	StartDate	string		必须	开始日期,例如:2016-07-01
    84  //	EndDate		string		必须	结束日期,例如:2016-07-03
    85  //	Granularity	string		必须	粒度,取值:5min / hour /day
    86  //	Domains		[]string	必须	域名列表
    87  //	Opts                            非必须   可选项
    88  
    89  func (m *CdnManager) GetBandwidthData(startDate, endDate, granularity string,
    90  	domainList []string, opts ...BandwidthOption,
    91  ) (bandwidthData TrafficResp, err error) {
    92  	var options options
    93  	for _, opt := range opts {
    94  		opt.Apply(&options)
    95  	}
    96  	domains := strings.Join(domainList, ";")
    97  	reqBody := TrafficReq{
    98  		StartDate:   startDate,
    99  		EndDate:     endDate,
   100  		Granularity: granularity,
   101  		Domains:     domains,
   102  	}
   103  	if options.dataType.Valid() {
   104  		reqBody.DataType = options.dataType.String()
   105  	}
   106  
   107  	resData, reqErr := postRequest(m.mac, "/v2/tune/bandwidth", reqBody)
   108  	if reqErr != nil {
   109  		err = reqErr
   110  		return
   111  	}
   112  	umErr := json.Unmarshal(resData, &bandwidthData)
   113  	if umErr != nil {
   114  		err = umErr
   115  		return
   116  	}
   117  	return
   118  }
   119  
   120  type FluxOption Option
   121  
   122  func WithFluxDataType(dataType DataType) FluxOption {
   123  	if DataTypeFlow <= dataType && dataType <= DataType302mFlow {
   124  		return _WithDataType(dataType)
   125  	}
   126  	panic("cdn: invalid DataType for GetFluxData: " + dataType.String())
   127  }
   128  
   129  // GetFluxData 方法用来获取域名访问流量数据
   130  //
   131  //	StartDate	string		必须	开始日期,例如:2016-07-01
   132  //	EndDate		string		必须	结束日期,例如:2016-07-03
   133  //	Granularity	string		必须	粒度,取值:5min / hour /day
   134  //	Domains		[]string	必须	域名列表
   135  //	Opts                            非必须   可选项
   136  func (m *CdnManager) GetFluxData(startDate, endDate, granularity string,
   137  	domainList []string, opts ...FluxOption,
   138  ) (fluxData TrafficResp, err error) {
   139  	var options options
   140  	for _, opt := range opts {
   141  		opt.Apply(&options)
   142  	}
   143  	domains := strings.Join(domainList, ";")
   144  	reqBody := TrafficReq{
   145  		StartDate:   startDate,
   146  		EndDate:     endDate,
   147  		Granularity: granularity,
   148  		Domains:     domains,
   149  	}
   150  	if options.dataType.Valid() {
   151  		reqBody.DataType = options.dataType.String()
   152  	}
   153  
   154  	resData, reqErr := postRequest(m.mac, "/v2/tune/flux", reqBody)
   155  	if reqErr != nil {
   156  		err = reqErr
   157  		return
   158  	}
   159  
   160  	umErr := json.Unmarshal(resData, &fluxData)
   161  	if umErr != nil {
   162  		err = umErr
   163  		return
   164  	}
   165  
   166  	return
   167  }
   168  
   169  // RefreshReq 为缓存刷新请求内容
   170  type RefreshReq struct {
   171  	Urls []string `json:"urls"`
   172  	Dirs []string `json:"dirs"`
   173  }
   174  
   175  // RefreshResp 缓存刷新响应内容
   176  type RefreshResp struct {
   177  	Code          int      `json:"code"`
   178  	Error         string   `json:"error"`
   179  	RequestID     string   `json:"requestId,omitempty"`
   180  	InvalidUrls   []string `json:"invalidUrls,omitempty"`
   181  	InvalidDirs   []string `json:"invalidDirs,omitempty"`
   182  	URLQuotaDay   int      `json:"urlQuotaDay,omitempty"`
   183  	URLSurplusDay int      `json:"urlSurplusDay,omitempty"`
   184  	DirQuotaDay   int      `json:"dirQuotaDay,omitempty"`
   185  	DirSurplusDay int      `json:"dirSurplusDay,omitempty"`
   186  }
   187  
   188  // RefreshUrlsAndDirs 方法用来刷新文件或目录
   189  // urls	要刷新的单个url列表,单次方法调用总数不超过100条;单个url,即一个具体的url,
   190  // 例如:http://bar.foo.com/index.html
   191  // dirs	要刷新的目录url列表,单次方法调用总数不超过10条;目录dir,即表示一个目录级的url,
   192  // 例如:http://bar.foo.com/dir/,
   193  func (m *CdnManager) RefreshUrlsAndDirs(urls, dirs []string) (result RefreshResp, err error) {
   194  	if len(urls) > 100 {
   195  		err = errors.New("urls count exceeds the limit of 100")
   196  		return
   197  	}
   198  	if len(dirs) > 10 {
   199  		err = errors.New("dirs count exceeds the limit of 10")
   200  		return
   201  	}
   202  
   203  	reqBody := RefreshReq{
   204  		Urls: urls,
   205  		Dirs: dirs,
   206  	}
   207  
   208  	resData, reqErr := postRequest(m.mac, "/v2/tune/refresh", reqBody)
   209  	if reqErr != nil {
   210  		err = reqErr
   211  		return
   212  	}
   213  	umErr := json.Unmarshal(resData, &result)
   214  	if umErr != nil {
   215  		err = reqErr
   216  		return
   217  	}
   218  
   219  	return
   220  }
   221  
   222  // RefreshUrls 刷新文件
   223  func (m *CdnManager) RefreshUrls(urls []string) (result RefreshResp, err error) {
   224  	return m.RefreshUrlsAndDirs(urls, nil)
   225  }
   226  
   227  // RefreshDirs 刷新目录
   228  func (m *CdnManager) RefreshDirs(dirs []string) (result RefreshResp, err error) {
   229  	return m.RefreshUrlsAndDirs(nil, dirs)
   230  }
   231  
   232  // PrefetchReq 文件预取请求内容
   233  type PrefetchReq struct {
   234  	Urls []string `json:"urls"`
   235  }
   236  
   237  // PrefetchResp 文件预取响应内容
   238  type PrefetchResp struct {
   239  	Code        int      `json:"code"`
   240  	Error       string   `json:"error"`
   241  	RequestID   string   `json:"requestId,omitempty"`
   242  	InvalidUrls []string `json:"invalidUrls,omitempty"`
   243  	QuotaDay    int      `json:"quotaDay,omitempty"`
   244  	SurplusDay  int      `json:"surplusDay,omitempty"`
   245  }
   246  
   247  // PrefetchUrls 预取文件链接,每次最多不可以超过100条
   248  func (m *CdnManager) PrefetchUrls(urls []string) (result PrefetchResp, err error) {
   249  	if len(urls) > 100 {
   250  		err = errors.New("urls count exceeds the limit of 100")
   251  		return
   252  	}
   253  
   254  	reqBody := PrefetchReq{
   255  		Urls: urls,
   256  	}
   257  
   258  	resData, reqErr := postRequest(m.mac, "/v2/tune/prefetch", reqBody)
   259  	if reqErr != nil {
   260  		err = reqErr
   261  		return
   262  	}
   263  
   264  	umErr := json.Unmarshal(resData, &result)
   265  	if umErr != nil {
   266  		err = umErr
   267  		return
   268  	}
   269  
   270  	return
   271  }
   272  
   273  // ListLogRequest 日志下载请求内容
   274  type ListLogRequest struct {
   275  	Day     string `json:"day"`
   276  	Domains string `json:"domains"`
   277  }
   278  
   279  // ListLogResult 日志下载相应内容
   280  type ListLogResult struct {
   281  	Code  int                        `json:"code"`
   282  	Error string                     `json:"error"`
   283  	Data  map[string][]LogDomainInfo `json:"data"`
   284  }
   285  
   286  // LogDomainInfo 日志下载信息
   287  type LogDomainInfo struct {
   288  	Name         string `json:"name"`
   289  	Size         int64  `json:"size"`
   290  	ModifiedTime int64  `json:"mtime"`
   291  	URL          string `json:"url"`
   292  }
   293  
   294  // GetCdnLogList 获取CDN域名访问日志的下载链接
   295  func (m *CdnManager) GetCdnLogList(day string, domains []string) (
   296  	listLogResult ListLogResult, err error,
   297  ) {
   298  	// new log query request
   299  	logReq := ListLogRequest{
   300  		Day:     day,
   301  		Domains: strings.Join(domains, ";"),
   302  	}
   303  
   304  	resData, reqErr := postRequest(m.mac, "/v2/tune/log/list", logReq)
   305  	if reqErr != nil {
   306  		err = fmt.Errorf("get response error, %s", reqErr)
   307  		return
   308  	}
   309  
   310  	if decodeErr := json.Unmarshal(resData, &listLogResult); decodeErr != nil {
   311  		err = fmt.Errorf("get response error, %s", decodeErr)
   312  		return
   313  	}
   314  
   315  	if listLogResult.Error != "" {
   316  		err = fmt.Errorf("get log list error, %d %s", listLogResult.Code, listLogResult.Error)
   317  		return
   318  	}
   319  
   320  	return
   321  }
   322  
   323  // RequestWithBody 带body对api发出请求并且返回response body
   324  func postRequest(mac *auth.Credentials, path string, body interface{}) (resData []byte,
   325  	err error,
   326  ) {
   327  	urlStr := fmt.Sprintf("%s%s", FusionHost, path)
   328  	reqData, _ := json.Marshal(body)
   329  	req, reqErr := http.NewRequest("POST", urlStr, bytes.NewReader(reqData))
   330  	if reqErr != nil {
   331  		err = reqErr
   332  		return
   333  	}
   334  
   335  	accessToken, signErr := mac.SignRequest(req)
   336  	if signErr != nil {
   337  		err = signErr
   338  		return
   339  	}
   340  
   341  	req.Header.Add("Authorization", "QBox "+accessToken)
   342  	req.Header.Add("Content-Type", "application/json")
   343  
   344  	resp, respErr := http.DefaultClient.Do(req)
   345  	if respErr != nil {
   346  		err = respErr
   347  		return
   348  	}
   349  	defer resp.Body.Close()
   350  
   351  	resData, ioErr := io.ReadAll(resp.Body)
   352  	if ioErr != nil {
   353  		err = ioErr
   354  		return
   355  	}
   356  
   357  	return
   358  }