67 lines
1.8 KiB
Go
67 lines
1.8 KiB
Go
// Copyright 2022 E99p1ant. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package storage
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/thanhpk/randstr"
|
|
"github.com/wuhan005/gadget"
|
|
|
|
"github.com/tamakyi/TamaBox/internal/conf"
|
|
)
|
|
|
|
// UploadPictureToOSS upload user's avatar or background image to OSS.
|
|
// It returns the uploaded asset URL.
|
|
func UploadPictureToOSS(file multipart.File, _ *multipart.FileHeader) (string, error) {
|
|
// 读取文件头,校验是否为图片
|
|
header := make([]byte, 512)
|
|
n, err := file.Read(header)
|
|
if err != nil && err != io.EOF {
|
|
return "", errors.Wrap(err, "read file header")
|
|
}
|
|
if n == 0 {
|
|
return "", errors.New("empty file")
|
|
}
|
|
if !isSupportedImage(header[:n]) {
|
|
return "", errors.New("不支持的文件格式,仅允许 JPEG、PNG、GIF、WebP 图片")
|
|
}
|
|
// 重置文件指针
|
|
if _, err := file.Seek(0, io.SeekStart); err != nil {
|
|
return "", errors.Wrap(err, "seek file")
|
|
}
|
|
|
|
// 获取共享 OSS bucket
|
|
bucket, err := GetOSSBucket()
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "get OSS bucket")
|
|
}
|
|
|
|
now := time.Now()
|
|
year := now.Year()
|
|
month := int(now.Month())
|
|
day := now.Day()
|
|
|
|
key := fmt.Sprintf("%s%d/%02d/%02d/%s", PictureKeyPrefix, year, month, day, randstr.Hex(15))
|
|
|
|
if err := gadget.Retry(5, func() error {
|
|
if err := bucket.PutObject(key, file); err != nil {
|
|
return errors.Wrap(err, "put object")
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return "", errors.Wrap(err, "retry 5 times")
|
|
}
|
|
|
|
if conf.Upload.AliyunBucketCDNHost != "" {
|
|
return fmt.Sprintf("https://%s/%s", conf.Upload.AliyunBucketCDNHost, key), nil
|
|
}
|
|
return fmt.Sprintf("https://%s.%s/%s", conf.Upload.AliyunBucket, conf.Upload.AliyunEndpoint, key), nil
|
|
}
|