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 }