// 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/huaweicloud/huaweicloud-sdk-go-obs/obs" "io" "net/http" ) type HuaweiOBSProvider struct { buckerName string client *obs.ObsClient } func NewHuaweiOBSProvider() *HuaweiOBSProvider { return &HuaweiOBSProvider{} } func (this *HuaweiOBSProvider) Init(options ossconfigs.OSSOptions, bucketName string) error { realOptions, ok := options.(*ossconfigs.HuaweiOBSProviderOptions) if !ok { return errors.New("invalid options for 'HuaweiOBSProvider'") } this.buckerName = bucketName client, err := obs.New(realOptions.AccessKeyId, realOptions.AccessKeySecret, "https://"+realOptions.Endpoint) if err != nil { return err } this.client = client return nil } func (this *HuaweiOBSProvider) Head(key string) (httpResponse *http.Response, nativeErrCode string, err error) { var input = &obs.HeadObjectInput{ Bucket: this.buckerName, Key: key, } output, respErr := this.client.HeadObject(input) if respErr != nil { nativeErrCode, err = this.parseErr(respErr) return } httpResponse = &http.Response{ StatusCode: output.StatusCode, ContentLength: 0, Header: this.formatHeaders(output.ResponseHeaders), Body: io.NopCloser(bytes.NewReader(nil)), } return } func (this *HuaweiOBSProvider) Get(key string) (httpResponse *http.Response, nativeErrCode string, err error) { var input = &obs.GetObjectInput{} input.Bucket = this.buckerName input.Key = key output, respErr := this.client.GetObject(input) if respErr != nil { nativeErrCode, err = this.parseErr(respErr) return } httpResponse = &http.Response{ StatusCode: output.StatusCode, ContentLength: output.ContentLength, Header: this.formatHeaders(output.ResponseHeaders), Body: output.Body, } return } func (this *HuaweiOBSProvider) 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) } var input = &obs.GetObjectInput{} input.Bucket = this.buckerName input.Key = key input.RangeStart = start input.RangeEnd = end output, respErr := this.client.GetObject(input) if respErr != nil { nativeErrCode, err = this.parseErr(respErr) return } httpResponse = &http.Response{ StatusCode: output.StatusCode, ContentLength: output.ContentLength, Header: this.formatHeaders(output.ResponseHeaders), Body: output.Body, } return } func (this *HuaweiOBSProvider) parseErr(err error) (errCode string, resultErr error) { if err == nil { return } resultErr = err respErr, ok := err.(obs.ObsError) 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 *HuaweiOBSProvider) formatHeaders(rawHeader http.Header) (resultHeader http.Header) { resultHeader = http.Header{} for k, v := range rawHeader { if k == "x-reserved" { continue } resultHeader[http.CanonicalHeaderKey(k)] = v } return resultHeader }