Files
waf-platform/EdgeNode/internal/oss/provider_aliyun_oss.go
2026-02-04 20:27:13 +08:00

164 lines
3.6 KiB
Go

// 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/aliyun/aliyun-oss-go-sdk/oss"
"github.com/iwind/TeaGo/types"
"io"
"net/http"
)
type AliyunOSSProvider struct {
bucket *oss.Bucket
}
func NewAliyunOSSProvider() *AliyunOSSProvider {
return &AliyunOSSProvider{}
}
func (this *AliyunOSSProvider) Init(options ossconfigs.OSSOptions, bucketName string) error {
realOptions, ok := options.(*ossconfigs.AliyunOSSProviderOptions)
if !ok {
return errors.New("invalid options for 'AliyunOSSProvider'")
}
client, err := oss.New(realOptions.Endpoint, realOptions.AccessKeyId, realOptions.AccessKeySecret)
if err != nil {
return err
}
bucket, err := client.Bucket(bucketName)
if err != nil {
return err
}
this.bucket = bucket
return nil
}
func (this *AliyunOSSProvider) Head(key string) (httpResponse *http.Response, nativeErrCode string, err error) {
header, respErr := this.bucket.GetObjectMeta(key)
if err != nil {
nativeErrCode, err = this.parseErr(respErr)
return
}
// not found
if len(header) == 0 {
header = http.Header{"Content-Length": []string{"0"}}
httpResponse = &http.Response{
StatusCode: http.StatusNotFound,
Header: header,
Body: io.NopCloser(bytes.NewReader(nil)),
ContentLength: 0,
}
return
}
httpResponse = &http.Response{
StatusCode: http.StatusOK,
Header: header,
Body: io.NopCloser(bytes.NewReader(nil)),
ContentLength: types.Int64(header.Get("Content-Length")),
}
return
}
func (this *AliyunOSSProvider) Get(key string) (httpResponse *http.Response, nativeErrCode string, err error) {
body, respErr := this.bucket.GetObject(key)
if respErr != nil {
nativeErrCode, err = this.parseErr(respErr)
return
}
resp, ok := body.(*oss.Response)
if ok {
httpResponse = &http.Response{
StatusCode: http.StatusOK,
Header: resp.Headers,
Body: resp.Body,
ContentLength: types.Int64(resp.Headers.Get("Content-Length")),
}
return
}
httpResponse = &http.Response{
StatusCode: http.StatusOK,
Body: body,
}
return
}
func (this *AliyunOSSProvider) 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)
}
body, respErr := this.bucket.GetObject(key, oss.Range(start, end))
if respErr != nil {
nativeErrCode, err = this.parseErr(respErr)
return
}
resp, ok := body.(*oss.Response)
if ok {
httpResponse = &http.Response{
StatusCode: resp.StatusCode,
Header: resp.Headers,
Body: resp.Body,
ContentLength: types.Int64(resp.Headers.Get("Content-Length")),
}
return
}
httpResponse = &http.Response{
StatusCode: http.StatusPartialContent,
Body: body,
}
return
}
func (this *AliyunOSSProvider) parseErr(err error) (errCode string, resultErr error) {
if err == nil {
return
}
resultErr = err
serviceErr, ok := err.(oss.ServiceError)
if ok {
errCode = serviceErr.Code
// 特殊错误
if errCode == "NoSuchBucket" {
resultErr = errNoBucket
return
}
if errCode == "NoSuchKey" {
resultErr = errNotFound
}
if errCode == "RequestTimeout" {
resultErr = errRequestTimeout
return
}
}
return
}