// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn . //go:build plus package oss import ( "bytes" "errors" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ossconfigs" "github.com/baidubce/bce-sdk-go/bce" "github.com/baidubce/bce-sdk-go/services/bos" "github.com/baidubce/bce-sdk-go/services/bos/api" "github.com/iwind/TeaGo/types" "io" "net/http" ) type BaiduBOSProvider struct { bucketName string client *bos.Client } func NewBaiduBOSProvider() *BaiduBOSProvider { return &BaiduBOSProvider{} } func (this *BaiduBOSProvider) Init(options ossconfigs.OSSOptions, bucketName string) error { realOptions, ok := options.(*ossconfigs.BaiduBOSProviderOptions) if !ok { return errors.New("invalid options for 'BaiduOBSProvider'") } this.bucketName = bucketName client, err := bos.NewClient(realOptions.AccessKey, realOptions.SecretKey, "https://"+realOptions.Endpoint) if err != nil { return err } this.client = client return nil } func (this *BaiduBOSProvider) Head(key string) (httpResponse *http.Response, nativeErrCode string, err error) { result, respErr := this.client.GetObjectMeta(this.bucketName, key) if respErr != nil { nativeErrCode, err = this.parseErr(respErr) return } httpResponse = &http.Response{ StatusCode: http.StatusOK, Header: this.composeHeader(result.ObjectMeta), ContentLength: result.ContentLength, Body: io.NopCloser(bytes.NewReader(nil)), } return } func (this *BaiduBOSProvider) Get(key string) (httpResponse *http.Response, nativeErrCode string, err error) { result, respErr := this.client.BasicGetObject(this.bucketName, key) if respErr != nil { nativeErrCode, err = this.parseErr(respErr) return } httpResponse = &http.Response{ StatusCode: http.StatusOK, Header: this.composeHeader(result.ObjectMeta), ContentLength: result.ContentLength, Body: result.Body, } return } func (this *BaiduBOSProvider) GetRange(key string, bytesRange string) (httpResponse *http.Response, nativeErrCode string, err error) { rangeResult, parseOk := httpRequestParseRangeHeader(bytesRange) if !parseOk || len(rangeResult) == 0 { return this.Get(key) } var firstRange = rangeResult[0] var start = firstRange.Start() var end = firstRange.End() if start < 0 || end < 0 || start > end { return this.Get(key) } result, respErr := this.client.GetObject(this.bucketName, key, nil, start, end) if respErr != nil { nativeErrCode, err = this.parseErr(respErr) return } var statusCode = http.StatusOK if len(result.ContentRange) > 0 { statusCode = http.StatusPartialContent } httpResponse = &http.Response{ StatusCode: statusCode, Header: this.composeHeader(result.ObjectMeta), ContentLength: result.ContentLength, Body: result.Body, } return } func (this *BaiduBOSProvider) parseErr(err error) (errCode string, resultErr error) { if err == nil { return } resultErr = err respErr, ok := err.(*bce.BceServiceError) if ok { errCode = respErr.Code } // 特殊错误 if errCode == "NoSuchBucket" { resultErr = errNoBucket return } if errCode == "NoSuchKey" { resultErr = errNotFound return } if errCode == "RequestTimeout" { resultErr = errRequestTimeout return } return } func (this *BaiduBOSProvider) composeHeader(result api.ObjectMeta) http.Header { var header = http.Header{} if len(result.CacheControl) > 0 { header.Set("Cache-Control", result.CacheControl) } if len(result.ContentDisposition) > 0 { header.Set("Content-Disposition", result.ContentDisposition) } if len(result.ContentEncoding) > 0 { header.Set("Content-Encoding", result.ContentEncoding) } header.Set("Content-Length", types.String(result.ContentLength)) if len(result.ContentRange) > 0 { header.Set("Content-Range", result.ContentRange) } if len(result.ContentType) > 0 { header.Set("Content-Type", result.ContentType) } if len(result.ContentMD5) > 0 { header["Content-MD5"] = []string{result.ContentMD5} } if len(result.ContentSha256) > 0 { header.Set("Content-Sha256", result.ContentSha256) } if len(result.ContentCrc32) > 0 { header.Set("Content-Crc32", result.ContentCrc32) } if len(result.Expires) > 0 { header.Set("Expires", result.Expires) } if len(result.LastModified) > 0 { header.Set("Last-Modified", result.LastModified) } if len(result.ETag) > 0 { header["ETag"] = []string{result.ETag} } return header }