144 lines
4.0 KiB
Go
144 lines
4.0 KiB
Go
package util
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
|
"github.com/aliyun/credentials-go/credentials"
|
|
"github.com/topfans/backend/pkg/logger"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// OSSConfig OSS 配置
|
|
type OSSConfig struct {
|
|
Region string
|
|
BucketName string
|
|
RoleArn string
|
|
AccessKeyID string
|
|
AccessKeySecret string
|
|
}
|
|
|
|
// UploadImageToOSS 下载图片并上传到 OSS
|
|
func UploadImageToOSS(config OSSConfig, imageURL string, ossKey string) (string, error) {
|
|
// 1. 下载图片到内存
|
|
resp, err := http.Get(imageURL)
|
|
if err != nil {
|
|
return "", fmt.Errorf("下载图片失败: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", fmt.Errorf("下载图片失败,状态码: %d", resp.StatusCode)
|
|
}
|
|
|
|
imageData, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return "", fmt.Errorf("读取图片数据失败: %w", err)
|
|
}
|
|
|
|
// 2. 获取 STS 临时凭证
|
|
credConfig := new(credentials.Config).
|
|
SetType("ram_role_arn").
|
|
SetAccessKeyId(config.AccessKeyID).
|
|
SetAccessKeySecret(config.AccessKeySecret).
|
|
SetRoleArn(config.RoleArn).
|
|
SetRoleSessionName("topfans-asset-upload").
|
|
SetPolicy("").
|
|
SetRoleSessionExpiration(3600)
|
|
|
|
provider, err := credentials.NewCredential(credConfig)
|
|
if err != nil {
|
|
return "", fmt.Errorf("创建凭证提供器失败: %w", err)
|
|
}
|
|
|
|
cred, err := provider.GetCredential()
|
|
if err != nil {
|
|
return "", fmt.Errorf("获取临时凭证失败: %w", err)
|
|
}
|
|
|
|
// 3. 创建 OSS 客户端
|
|
endpoint := fmt.Sprintf("https://oss-%s.aliyuncs.com", config.Region)
|
|
client, err := oss.New(endpoint, *cred.AccessKeyId, *cred.AccessKeySecret,
|
|
oss.SecurityToken(*cred.SecurityToken))
|
|
if err != nil {
|
|
return "", fmt.Errorf("创建OSS客户端失败: %w", err)
|
|
}
|
|
|
|
// 4. 获取 Bucket
|
|
bucket, err := client.Bucket(config.BucketName)
|
|
if err != nil {
|
|
return "", fmt.Errorf("获取Bucket失败: %w", err)
|
|
}
|
|
|
|
// 5. 上传图片
|
|
err = bucket.PutObject(ossKey, bytes.NewReader(imageData))
|
|
if err != nil {
|
|
return "", fmt.Errorf("上传图片到OSS失败: %w", err)
|
|
}
|
|
|
|
// 6. 构建 OSS URL
|
|
ossURL := fmt.Sprintf("https://%s.oss-%s.aliyuncs.com/%s", config.BucketName, config.Region, ossKey)
|
|
|
|
logger.Logger.Info("图片上传到OSS成功",
|
|
zap.String("oss_key", ossKey),
|
|
zap.String("oss_url", ossURL),
|
|
)
|
|
|
|
return ossURL, nil
|
|
}
|
|
|
|
// DeleteObjectFromOSS 删除 OSS 对象(用于阶段一取消后清理素材)
|
|
func DeleteObjectFromOSS(config OSSConfig, ossKey string) error {
|
|
if ossKey == "" {
|
|
return fmt.Errorf("ossKey不能为空")
|
|
}
|
|
|
|
// 获取 STS 临时凭证
|
|
credConfig := new(credentials.Config).
|
|
SetType("ram_role_arn").
|
|
SetAccessKeyId(config.AccessKeyID).
|
|
SetAccessKeySecret(config.AccessKeySecret).
|
|
SetRoleArn(config.RoleArn).
|
|
SetRoleSessionName("topfans-asset-delete").
|
|
SetPolicy("").
|
|
SetRoleSessionExpiration(3600)
|
|
|
|
provider, err := credentials.NewCredential(credConfig)
|
|
if err != nil {
|
|
return fmt.Errorf("创建凭证提供器失败: %w", err)
|
|
}
|
|
cred, err := provider.GetCredential()
|
|
if err != nil {
|
|
return fmt.Errorf("获取临时凭证失败: %w", err)
|
|
}
|
|
|
|
endpoint := fmt.Sprintf("https://oss-%s.aliyuncs.com", config.Region)
|
|
client, err := oss.New(endpoint, *cred.AccessKeyId, *cred.AccessKeySecret,
|
|
oss.SecurityToken(*cred.SecurityToken))
|
|
if err != nil {
|
|
return fmt.Errorf("创建OSS客户端失败: %w", err)
|
|
}
|
|
bucket, err := client.Bucket(config.BucketName)
|
|
if err != nil {
|
|
return fmt.Errorf("获取Bucket失败: %w", err)
|
|
}
|
|
|
|
if err := bucket.DeleteObject(ossKey); err != nil {
|
|
return fmt.Errorf("删除OSS对象失败: %w", err)
|
|
}
|
|
|
|
logger.Logger.Info("删除OSS对象成功", zap.String("oss_key", ossKey))
|
|
return nil
|
|
}
|
|
|
|
// GenerateOSSKey 生成 OSS 对象键(路径)
|
|
// 格式: asset/{user_id}/{star_id}/covers/{asset_id}_{timestamp}.png
|
|
func GenerateOSSKey(userID, starID, assetID int64) string {
|
|
timestamp := time.Now().Unix()
|
|
return fmt.Sprintf("asset/%d/%d/covers/%d_%d.png", userID, starID, assetID, timestamp)
|
|
}
|