You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sonic/service/storage/impl/aliyun.go

175 lines
5.7 KiB
Go

package filestorageimpl
import (
"context"
"image"
"io"
"mime/multipart"
"net/url"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/model/property"
"github.com/go-sonic/sonic/service"
"github.com/go-sonic/sonic/util/xerr"
)
type Aliyun struct {
OptionService service.OptionService
}
func NewAliyun(optionService service.OptionService) *Aliyun {
return &Aliyun{
OptionService: optionService,
}
}
type aliyunClient struct {
*oss.Client
Bucket *oss.Bucket
BucketName string
EndPoint string
Source string
Style string
ThubmnailStyle string
Domain string
Protocol string
}
func (a *Aliyun) Upload(ctx context.Context, fileHeader *multipart.FileHeader) (*dto.AttachmentDTO, error) {
aliyunClientInstance, err := a.getAliOSSClient(ctx)
if err != nil {
return nil, err
}
basePath := aliyunClientInstance.Protocol + aliyunClientInstance.BucketName + "." + aliyunClientInstance.EndPoint
if aliyunClientInstance.Domain != "" {
basePath = aliyunClientInstance.Protocol + aliyunClientInstance.Domain
}
fd, err := newURLFileDescriptor(
withBaseURL(basePath),
withSubURLPath(aliyunClientInstance.Source),
withShouldRenameURLOption(commonRenamePredicateFunc(ctx, consts.AttachmentTypeAliOSS)),
withOriginalNameURLOption(fileHeader.Filename),
)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError)
}
file, err := fileHeader.Open()
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError).WithMsg("open upload file error")
}
defer file.Close()
err = aliyunClientInstance.Bucket.PutObject(fd.getRelativePath(), file)
if err != nil {
return nil, xerr.WithMsg(err, "upload to aliyun oss error: "+err.Error()).WithStatus(xerr.StatusInternalServerError)
}
mediaType, _ := getFileContentType(file)
result := &dto.AttachmentDTO{
Name: fd.getFileName(),
Path: fd.getRelativePath() + aliyunClientInstance.Style,
FileKey: fd.getRelativePath(),
Suffix: fd.getExtensionName(),
MediaType: mediaType,
AttachmentType: consts.AttachmentTypeAliOSS,
Size: fileHeader.Size,
}
_, err = file.Seek(0, io.SeekStart)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError)
}
err = handleImageMeta(file, result, func(_ image.Image) (string, error) {
if aliyunClientInstance.ThubmnailStyle != "" {
return fd.getRelativePath() + aliyunClientInstance.ThubmnailStyle, nil
} else {
return fd.getRelativePath(), nil
}
})
if err != nil {
return nil, err
}
return result, nil
}
func (a *Aliyun) Delete(ctx context.Context, fileKey string) error {
aliyunClientInstance, err := a.getAliOSSClient(ctx)
if err != nil {
return err
}
err = aliyunClientInstance.Bucket.DeleteObject(fileKey)
if err != nil {
return xerr.WithMsg(err, "delete file err from aliyun oss").WithStatus(xerr.StatusInternalServerError)
}
return nil
}
func (a *Aliyun) GetAttachmentType() consts.AttachmentType {
return consts.AttachmentTypeAliOSS
}
func (a *Aliyun) GetFilePath(ctx context.Context, relativePath string) (string, error) {
aliyunClientInstance, err := a.getAliOSSClient(ctx)
if err != nil {
return "", err
}
basePath := aliyunClientInstance.Protocol + aliyunClientInstance.BucketName + "." + aliyunClientInstance.EndPoint
if aliyunClientInstance.Domain != "" {
basePath = aliyunClientInstance.Protocol + aliyunClientInstance.Domain
}
fullPath, _ := url.JoinPath(basePath, relativePath)
fullPath, _ = url.PathUnescape(fullPath)
return fullPath, nil
}
func (a *Aliyun) getAliOSSClient(ctx context.Context) (*aliyunClient, error) {
getClientProperty := func(propertyValue *string, property property.Property, e error) error {
if e != nil {
return e
}
value, err := a.OptionService.GetOrByDefaultWithErr(ctx, property, property.DefaultValue)
if err != nil {
return err
}
strValue, ok := value.(string)
if !ok {
return xerr.WithStatus(nil, xerr.StatusBadRequest).WithErrMsgf("wrong property type")
}
*propertyValue = strValue
return nil
}
var endPoint, bucketName, accessKey, accessSecret, source, styleRule, thumbnailStyleRule, domain, protocol string
err := getClientProperty(&endPoint, property.AliOssEndpoint, nil)
err = getClientProperty(&bucketName, property.AliOssBucketName, err)
err = getClientProperty(&accessKey, property.AliOssAccessKey, err)
err = getClientProperty(&accessSecret, property.AliOssAccessSecret, err)
err = getClientProperty(&source, property.AliOssSource, err)
err = getClientProperty(&styleRule, property.AliOssStyleRule, err)
err = getClientProperty(&thumbnailStyleRule, property.AliOssThumbnailStyleRule, err)
err = getClientProperty(&domain, property.AliOssDomain, err)
err = getClientProperty(&protocol, property.AliOssProtocol, err)
if err != nil {
return nil, err
}
client, err := oss.New(endPoint, accessKey, accessSecret, oss.Timeout(2, 60), oss.EnableCRC(true))
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError).WithMsg("failed to initialize aliyun oss client: " + err.Error())
}
aliyunClientInstance := &aliyunClient{}
aliyunClientInstance.Client = client
aliyunClientInstance.Source = source
aliyunClientInstance.BucketName = bucketName
aliyunClientInstance.EndPoint = endPoint
aliyunClientInstance.ThubmnailStyle = thumbnailStyleRule
aliyunClientInstance.Style = styleRule
aliyunClientInstance.Domain = domain
aliyunClientInstance.Protocol = protocol
aliyunClientInstance.Bucket, err = client.Bucket(bucketName)
if err != nil {
return nil, xerr.WithStatus(err, xerr.StatusInternalServerError).WithMsg("failed to initialize aliyun oss client bucket: " + err.Error())
}
return aliyunClientInstance, nil
}